Example #1
0
// respondToClient replies to the client when
// an entry is replicated on majority of servers
func (s *raftServer) updateLeaderCommitIndex(followers []int, matchIndex *utils.SyncIntIntMap) {

	for s.State() == LEADER {
		N := s.commitIndex.Get() + 1
		upto := N + 1

		for N <= upto {

			if !s.localLog.Exists(N) {
				break
			}

			i := 1
			for _, f := range followers {
				if j, _ := matchIndex.Get(f); j >= N {
					i++
					upto = max(upto, j)
				}
			}
			// followers do not include Leader
			if entry := s.localLog.Get(N); i > (len(followers)+1)/2 && entry.Term == s.Term() {
				s.writeToLog("Updating commitIndex to " + strconv.FormatInt(N, 10))
				s.commitIndex.Set(N)
			}
			N++
		}
		time.Sleep(NICE * time.Millisecond)
	}
}
Example #2
0
// handleFollowers ensures that followers are informed
// about new messages and lagging followers catch up
// AppendEntry and AppendEntryResponses occur in
// lockstep. aeToken is used to implement mutex like
// behaviour to ensure that a new AppendEntry message
// is sent only when response to previous AppendEntry
// message is received
func (s *raftServer) handleFollowers(followers []int, nextIndex *utils.SyncIntIntMap, matchIndex *utils.SyncIntIntMap, aeToken *utils.SyncIntIntMap) {
	for s.State() == LEADER {
		for _, f := range followers {
			lastIndex := s.localLog.TailIndex()
			n, ok := nextIndex.Get(f)
			if !ok {
				panic("nextIndex not found for follower " + strconv.Itoa(f))
			}

			unlocked, ok := aeToken.Get(f)

			if !ok {
				panic("aeToken not found for follower " + strconv.Itoa(f))
			}

			if lastIndex != 0 && lastIndex >= n && unlocked == 1 {
				aeToken.Set(f, 0)
				// send a new AppendEntry
				prevIndex := n - 1
				var prevTerm int64 = 0
				// n = 0 when we add first entry to the log
				if prevIndex > 0 {
					prevTerm = s.localLog.Get(prevIndex).Term
				}
				ae := &AppendEntry{Term: s.Term(), LeaderId: s.server.Pid(), PrevLogIndex: prevIndex, PrevLogTerm: prevTerm}
				ae.LeaderCommit = s.commitIndex.Get()
				ae.Entry = *s.localLog.Get(n)
				s.writeToLog("Replicating entry " + strconv.FormatInt(n, 10))
				s.server.Outbox() <- &cluster.Envelope{Pid: f, Msg: ae}
			}
		}
		time.Sleep(NICE * time.Millisecond)
	}
}