type Changer … // EnterJoint verifies that the outgoing (=right) majority config of the joint // config is empty and initializes it with a copy of the incoming (=left) // majority config. That is, it transitions from // // (1 2 3)&&() // // to // // (1 2 3)&&(1 2 3). // // The supplied changes are then applied to the incoming majority config, // resulting in a joint configuration that in terms of the Raft thesis[1] // (Section 4.3) corresponds to `C_{new,old}`. // // [1]: https://github.com/ongardie/dissertation/blob/master/online-trim.pdf func (c Changer) EnterJoint(autoLeave bool, ccs ...pb.ConfChangeSingle) (tracker.Config, tracker.ProgressMap, error) { … } // LeaveJoint transitions out of a joint configuration. It is an error to call // this method if the configuration is not joint, i.e. if the outgoing majority // config Voters[1] is empty. // // The outgoing majority config of the joint configuration will be removed, // that is, the incoming config is promoted as the sole decision maker. In the // notation of the Raft thesis[1] (Section 4.3), this method transitions from // `C_{new,old}` into `C_new`. // // At the same time, any staged learners (LearnersNext) the addition of which // was held back by an overlapping voter in the former outgoing config will be // inserted into Learners. // // [1]: https://github.com/ongardie/dissertation/blob/master/online-trim.pdf func (c Changer) LeaveJoint() (tracker.Config, tracker.ProgressMap, error) { … } // Simple carries out a series of configuration changes that (in aggregate) // mutates the incoming majority config Voters[0] by at most one. This method // will return an error if that is not the case, if the resulting quorum is // zero, or if the configuration is in a joint state (i.e. if there is an // outgoing configuration). func (c Changer) Simple(ccs ...pb.ConfChangeSingle) (tracker.Config, tracker.ProgressMap, error) { … } // apply a change to the configuration. By convention, changes to voters are // always made to the incoming majority config Voters[0]. Voters[1] is either // empty or preserves the outgoing majority configuration while in a joint state. func (c Changer) apply(cfg *tracker.Config, prs tracker.ProgressMap, ccs ...pb.ConfChangeSingle) error { … } // makeVoter adds or promotes the given ID to be a voter in the incoming // majority config. func (c Changer) makeVoter(cfg *tracker.Config, prs tracker.ProgressMap, id uint64) { … } // makeLearner makes the given ID a learner or stages it to be a learner once // an active joint configuration is exited. // // The former happens when the peer is not a part of the outgoing config, in // which case we either add a new learner or demote a voter in the incoming // config. // // The latter case occurs when the configuration is joint and the peer is a // voter in the outgoing config. In that case, we do not want to add the peer // as a learner because then we'd have to track a peer as a voter and learner // simultaneously. Instead, we add the learner to LearnersNext, so that it will // be added to Learners the moment the outgoing config is removed by // LeaveJoint(). func (c Changer) makeLearner(cfg *tracker.Config, prs tracker.ProgressMap, id uint64) { … } // remove this peer as a voter or learner from the incoming config. func (c Changer) remove(cfg *tracker.Config, prs tracker.ProgressMap, id uint64) { … } // initProgress initializes a new progress for the given node or learner. func (c Changer) initProgress(cfg *tracker.Config, prs tracker.ProgressMap, id uint64, isLearner bool) { … } // checkInvariants makes sure that the config and progress are compatible with // each other. This is used to check both what the Changer is initialized with, // as well as what it returns. func checkInvariants(cfg tracker.Config, prs tracker.ProgressMap) error { … } // checkAndCopy copies the tracker's config and progress map (deeply enough for // the purposes of the Changer) and returns those copies. It returns an error // if checkInvariants does. func (c Changer) checkAndCopy() (tracker.Config, tracker.ProgressMap, error) { … } // checkAndReturn calls checkInvariants on the input and returns either the // resulting error or the input. func checkAndReturn(cfg tracker.Config, prs tracker.ProgressMap) (tracker.Config, tracker.ProgressMap, error) { … } // err returns zero values and an error. func (c Changer) err(err error) (tracker.Config, tracker.ProgressMap, error) { … } // nilAwareAdd populates a map entry, creating the map if necessary. func nilAwareAdd(m *map[uint64]struct{ … } // nilAwareDelete deletes from a map, nil'ing the map itself if it is empty after. func nilAwareDelete(m *map[uint64]struct{ … } // symdiff returns the count of the symmetric difference between the sets of // uint64s, i.e. len( (l - r) \union (r - l)). func symdiff(l, r map[uint64]struct{ … } func joint(cfg tracker.Config) bool { … } func incoming(voters quorum.JointConfig) quorum.MajorityConfig { … } func outgoing(voters quorum.JointConfig) quorum.MajorityConfig { … } func outgoingPtr(voters *quorum.JointConfig) *quorum.MajorityConfig { … } // Describe prints the type and NodeID of the configuration changes as a // space-delimited string. func Describe(ccs ...pb.ConfChangeSingle) string { … }