// New instance set up for a fresh leader func NewLeaderVolatileState( clusterInfo *config.ClusterInfo, indexOfLastEntry LogIndex, ) (*LeaderVolatileState, error) { lvs := &LeaderVolatileState{ make(map[ServerId]LogIndex), make(map[ServerId]LogIndex), } err := clusterInfo.ForEachPeer( func(peerId ServerId) error { // #5.3-p8s4: When a leader first comes to power, it initializes // all nextIndex values to the index just after the last one in // its log (11 in Figure 7). lvs.NextIndex[peerId] = indexOfLastEntry + 1 // lvs.MatchIndex[peerId] = 0 return nil }, ) if err != nil { return nil, err } return lvs, nil }
// Helper method to find potential new commitIndex. // Returns the highest N possible that is higher than currentCommitIndex. // Returns 0 if no match found. // #RFS-L4: If there exists an N such that N > commitIndex, a majority // of matchIndex[i] >= N, and log[N].term == currentTerm: // set commitIndex = N (#5.3, #5.4) func FindNewerCommitIndex( ci *config.ClusterInfo, lvs *LeaderVolatileState, log LogReadOnly, currentTerm TermNo, currentCommitIndex LogIndex, ) (LogIndex, error) { indexOfLastEntry, err := log.GetIndexOfLastEntry() if err != nil { return 0, err } requiredMatches := ci.QuorumSizeForCluster() var matchingN LogIndex = 0 // cover all N > currentCommitIndex // stop when we pass the end of the log for N := currentCommitIndex + 1; N <= indexOfLastEntry; N++ { // check log[N].term termAtN, err := log.GetTermAtIndex(N) if err != nil { return 0, err } if termAtN > currentTerm { // term has gone too high for log[N].term == currentTerm // no point trying further break } if termAtN < currentTerm { continue } // finally, check for majority of matchIndex var foundMatches uint = 1 // 1 because we already match! for _, peerMatchIndex := range lvs.MatchIndex { if peerMatchIndex >= N { foundMatches++ } } if foundMatches >= requiredMatches { matchingN = N } } return matchingN, nil }
// New instance set up for a fresh election func NewCandidateVolatileState( clusterInfo *config.ClusterInfo, ) (*CandidateVolatileState, error) { cvs := &CandidateVolatileState{ 1, // assumes we always vote for ourself clusterInfo.QuorumSizeForCluster(), make(map[ServerId]bool), } err := clusterInfo.ForEachPeer( func(peerId ServerId) error { cvs.VotedPeers[peerId] = false return nil }, ) if err != nil { return nil, err } return cvs, nil }