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); }
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); }