Пример #1
0
// 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
}
Пример #2
0
// 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
}
Пример #3
0
// 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
}