public async Task <AppendEntriesResponse> Receive(AppendEntries appendEntries) { if (!_serversInClusterInCluster.Contains(appendEntries.LeaderId)) { AddNewServerToServersInCluster(appendEntries); } if (State is Leader) { BecomeFollowerAndMatchTerm(appendEntries.Term, appendEntries.LeaderId); } _lastAppendEntriesMessageId = appendEntries.MessageId; // If RPC request or response contains term T > currentTerm: // set currentTerm = T, convert to follower (§5.1) if (appendEntries.Term > CurrentTerm || State is Candidate) { BecomeFollowerAndMatchTerm(appendEntries.Term, appendEntries.LeaderId); } /* * 1.Reply false if term < currentTerm(�5.1) */ if (appendEntries.Term < CurrentTerm) { return(new AppendEntriesResponse(CurrentTerm, false, Id, appendEntries.LeaderId)); } if (appendEntries.Entry == null) { //todo heartbeat reset election timer return(new AppendEntriesResponse(CurrentTerm, true, Id, appendEntries.LeaderId)); } /* * 2.Reply false if log doesn�t contain an entry at prevLogIndex * whose term matches prevLogTerm(�5.3)*/ if (Log.Count > 0 && Log.Count > appendEntries.PreviousLogIndex && Log[appendEntries.PreviousLogIndex].Term != appendEntries.PreviousLogTerm) { return(new AppendEntriesResponse(CurrentTerm, false, Id, appendEntries.LeaderId)); } /* 3.If an existing entry conflicts with a new one(same index * but different terms), delete the existing entry and all that * follow it*/ var newEntry = appendEntries.Entry; if (Log.Count > 0 && Log.Count > appendEntries.PreviousLogIndex) { var existingEntry = Log[appendEntries.PreviousLogIndex]; if (existingEntry.Term != newEntry.Term) { Log.Remove(existingEntry); } } else if (Log.Count > 0 && Log.Count > appendEntries.PreviousLogIndex + 1) { var existingEntry = Log[appendEntries.PreviousLogIndex + 1]; if (existingEntry.Term != newEntry.Term) { Log.Remove(existingEntry); } } /* 4.Append any new entries not already in the log */ Log.Add(newEntry); CommitIndex = CommitIndex + 1; /* * 5.If leaderCommit > commitIndex, set commitIndex = * min(leaderCommit, index of last new entry) */ if (appendEntries.LeaderCommit > CommitIndex) { CommitIndex = Math.Min(appendEntries.LeaderCommit, Log.Count - 1); } /* If commitIndex > lastApplied: increment lastApplied, apply * log[lastApplied] to state machine(§5.3)*/ if (CommitIndex > LastApplied) { if (Log.Count > 1) { LastApplied++; } await _stateMachine.Apply(Log[LastApplied].Command); return(new AppendEntriesResponse(CurrentTerm, true, Id, appendEntries.LeaderId)); } return(new AppendEntriesResponse(CurrentTerm, false, Id, appendEntries.LeaderId)); }