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