Exemple #1
0
        private AppendEntriesResponse AppendEntries(string address, IHost host, ulong nextIndex)
        {
            AppendEntriesRequest request = new AppendEntriesRequest
            {
                LeaderId     = Id,
                Term         = _stateController.PersistentState.CurrentTerm,
                PrevLogIndex = _stateController.PersistentState.LastLogIndex,
                PrevLogTerm  = _stateController.PersistentState.LastLogTerm,
                LeaderCommit = _stateController.VolatileState.CommitIndex
            };

            if (_stateController.PersistentState.LastLogIndex >= nextIndex)
            {
                List <LogEntry> logEntries = _uncommittiedLogs.FindAll(w => w.Index >= nextIndex);
                if (logEntries != null && logEntries.Any())
                {
                    request.Entries = logEntries;
                }
            }

            AppendEntriesResponse response = host.AppendEntriesInvoke(request);

            if (!response.IsSuccess && _leaderVolatileStates[address].NextIndex != 0)
            {
                _leaderVolatileStates[address].NextIndex -= 1;
                response = AppendEntries(address, host, _leaderVolatileStates[address].NextIndex);
            }
            return(response);
        }
Exemple #2
0
        private void Heartbeat()
        {
            bool committedLog    = false;
            int  replicatedCount = 1;

            foreach (Peer peer in _node.Peers)
            {
                Task.Run(() =>
                {
                    try
                    {
                        DebugConsole.WriteLine($"Sync to follower({peer.Address})... term {_stateController.PersistentState.CurrentTerm}...");
                        AppendEntriesResponse response = AppendEntries(peer.Address, peer.RemoteClient, _leaderVolatileStates[peer.Address].NextIndex);
                        if (_node.EnsureExistGreaterTermAndChangeRole(response.Term))
                        {
                            return;
                        }

                        if (response.IsSuccess)
                        {
                            lock (_appliedLogLockObj)
                            {
                                _leaderVolatileStates[peer.Address].NextIndex   = _stateController.PersistentState.LastLogIndex + 1;
                                _leaderVolatileStates[peer.Address].MatchIndex += 1;

                                replicatedCount  += 1;
                                int majorityCount = _node.Peers.Count;
                                if (!committedLog && replicatedCount > majorityCount / 2 + 1)
                                {
                                    committedLog = true;
                                    CommitLogs();
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        DebugConsole.WriteLine(ex.Message);
                        //todo
                    }
                });
            }
        }
        public AppendEntriesResponse AppendEntries(AppendEntriesRequest request)
        {
            if (string.IsNullOrEmpty(LeaderId))
            {
                LeaderId = request.LeaderId;
            }
            if (request.Term == _stateController.PersistentState.CurrentTerm)
            {
                lock (this)
                {
                    _isFromLegalLeaderRequest = true;
                }
            }
            AppendEntriesResponse response = new AppendEntriesResponse();

            if (_stateController.PersistentState.Logs.Any())
            {
                LogEntry logEntry = _stateController.PersistentState.Logs.SingleOrDefault(w => w.Index == request.PrevLogIndex && w.Term == request.PrevLogTerm);
                if (logEntry == null)
                {
                    response.IsSuccess = false;
                    response.Term      = _stateController.PersistentState.CurrentTerm;
                    return(response);
                }

                LogEntry diffTermLogEntry = _stateController.PersistentState.Logs.SingleOrDefault(w => request.Entries.Exists(e => e.Index == w.Index && w.Term != e.Term));
                if (diffTermLogEntry != null)
                {
                    _stateController.PersistentState.Logs.RemoveRange((int)diffTermLogEntry.Index, _stateController.PersistentState.Logs.Count - (int)diffTermLogEntry.Index);
                }
                _stateController.PersistentState.Logs.AddRange(request.Entries);
            }

            if (request.LeaderCommit > _stateController.VolatileState.CommitIndex)
            {
                _stateController.UpdateTerm(request.Term);
                _stateController.UpdateCommitIndex(Math.Min(request.LeaderCommit, request.PrevLogIndex));
            }
            response.IsSuccess = true;
            response.Term      = _stateController.PersistentState.CurrentTerm;
            return(response);
        }