private void RemoveLogAndCancelStart(long startIndex, long endIndex) { for (long index = startIndex; index <= endIndex; ++index) { if (index > LastApplied && WaitApplyFutures.TryRemove(index, out var future)) { // 还没有applied的日志被删除, // 当发生在重新选举,但是旧的leader上还有一些没有提交的请求时, // 需要取消。 // 其中判断:index > LastApplied 不是必要的。 // Apply的时候已经TryRemove了,仅会成功一次。 future.SetCanceled(); } var key = ByteBuffer.Allocate(); key.WriteLong8(index); Logs.Remove(key.Bytes, key.Size); } }
private RaftLog FindMaxMajorityLog(long startIndex) { RaftLog lastMajorityLog = null; for (long index = startIndex; index <= LastIndex; /**/) { var raftLog = ReadLogStart(index); if (null == raftLog) { break; } index = raftLog.Index + 1; lastMajorityLog = raftLog; int MajorityCount = 0; Raft.Server.Config.ForEachConnector( (c) => { var cex = c as Server.ConnectorEx; if (cex.MatchIndex >= raftLog.Index) { ++MajorityCount; } }); // 没有达成多数派,中断循环。后面返回上一个majority,仍可能为null。 // 等于的时候加上自己就是多数派了。 if (MajorityCount < Raft.RaftConfig.HalfCount) { break; } } return(lastMajorityLog); } private void TryCommit(AppendEntries rpc, Server.ConnectorEx connector) { connector.NextIndex = rpc.Argument.LastEntryIndex + 1; connector.MatchIndex = rpc.Argument.LastEntryIndex; // 已经提交的,旧的 AppendEntries 的结果,不用继续处理了。 // 【注意】这个不是必要的,是一个小优化。 if (rpc.Argument.LastEntryIndex <= CommitIndex) { return; } // Rules for Servers // If there exists an N such that N > commitIndex, a majority // of matchIndex[i] ≥ N, and log[N].term == currentTerm: // set commitIndex = N(§5.3, §5.4). // TODO 对于 Leader CommitIndex 初始化问题。 var raftLog = FindMaxMajorityLog(CommitIndex + 1); if (null == raftLog) { return; // 一个多数派都没有找到。 } if (raftLog.Term != Term) { // 如果是上一个 Term 未提交的日志在这一次形成的多数派, // 不自动提交。 // 总是等待当前 Term 推进时,顺便提交它。 return; } CommitIndex = raftLog.Index; TryApply(raftLog); } private void TryApply(RaftLog lastApplyableLog) { if (null == lastApplyableLog) { logger.Error("lastApplyableLog is null."); return; } for (long index = LastApplied + 1; index <= lastApplyableLog.Index; /**/) { var raftLog = ReadLogStart(index); if (null == raftLog) { return; // end? } index = raftLog.Index + 1; if (Raft.RaftConfig.AutoKeyLocalStep > 0 && raftLog.Log.UniqueRequestId > 0) { // 这是防止请求重复执行用的。 // 需要对每个Raft.Agent的请求排队处理。 // see Net.cs Server.DispatchProtocol var appInstance = raftLog.Log.UniqueRequestId % Raft.RaftConfig.AutoKeyLocalStep; LastAppliedAppRpcSessionId[appInstance] = raftLog.Log.UniqueRequestId; } raftLog.Log.Apply(Raft.StateMachine); LastApplied = raftLog.Index; // 循环可能退出,在这里修改。 if (WaitApplyFutures.TryRemove(raftLog.Index, out var future)) { future.SetResult(0); } } }