Beispiel #1
0
        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));
        }