Exemplo n.º 1
0
Arquivo: Log.cs Projeto: e2wugui/zeze
        private int ProcessAppendEntriesResult(Server.ConnectorEx connector, Protocol p)
        {
            if (false == Raft.IsLeader)
            {
                return(Procedure.Success); // maybe close
            }
            var r = p as AppendEntries;

            if (r.IsTimeout)
            {
                TrySendAppendEntries(connector, r);  //resend
                return(Procedure.Success);
            }

            lock (Raft)
            {
                if (Raft.LogSequence.TrySetTerm(r.Result.Term))
                {
                    Raft.LeaderId = string.Empty; // 此时不知道谁是Leader。
                                                  // new term found.
                    Raft.ConvertStateTo(Raft.RaftState.Follower);
                    // 发现新的 Term,已经不是Leader,不能继续处理了。
                    // 直接返回。
                    connector.Pending = null;
                    return(Procedure.Success);
                }

                if (Raft.State != Raft.RaftState.Leader)
                {
                    connector.Pending = null;
                    return(Procedure.Success);
                }
            }

            if (r.Result.Success)
            {
                lock (Raft)
                {
                    TryCommit(r, connector);
                }
                // TryCommit 推进了NextIndex,
                // 可能日志没有复制完或者有新的AppendLog。
                // 尝试继续复制日志。
                // see TrySendAppendEntries 内的
                // “限制一次发送的日志数量”
                TrySendAppendEntries(connector, r);
                return(Procedure.Success);
            }

            lock (Raft)
            {
                // TODO raft.pdf 提到一个优化
                connector.NextIndex--;
                TrySendAppendEntries(connector, r);  //resend. use new NextIndex。
                return(Procedure.Success);
            }
        }
Exemplo n.º 2
0
Arquivo: Log.cs Projeto: e2wugui/zeze
        private void InstallSnapshot(string path, Server.ConnectorEx connector)
        {
            // 整个安装成功结束时设置。中间Break(return)不设置。
            // 后面 finally 里面使用这个标志
            bool InstallSuccess = false;

            logger.Debug("{0} InstallSnapshot Start... Path={1} ToConnector={2}",
                         Raft.Name, path, connector.Name);
            try
            {
                var  snapshotFile = new FileStream(path, FileMode.Open);
                long offset       = 0;
                var  buffer       = new byte[32 * 1024];
                var  FirstLog     = ReadLog(FirstIndex);
                var  trunkArg     = new InstallSnapshotArgument();
                trunkArg.Term              = Term;
                trunkArg.LeaderId          = Raft.LeaderId;
                trunkArg.LastIncludedIndex = FirstLog.Index;
                trunkArg.LastIncludedTerm  = FirstLog.Term;

                while (!trunkArg.Done && Raft.IsLeader)
                {
                    int rc = snapshotFile.Read(buffer);
                    trunkArg.Offset = offset;
                    trunkArg.Data   = new Binary(buffer, 0, rc);
                    trunkArg.Done   = rc < buffer.Length;
                    offset         += rc;

                    if (trunkArg.Done)
                    {
                        trunkArg.LastIncludedLog = new Binary(FirstLog.Encode());
                    }

                    while (Raft.IsLeader)
                    {
                        connector.HandshakeDoneEvent.WaitOne();
                        var future = new TaskCompletionSource <int>();
                        var r      = new InstallSnapshot()
                        {
                            Argument = trunkArg
                        };
                        if (!r.Send(connector.Socket,
                                    (_) =>
                        {
                            future.SetResult(0);
                            return(Procedure.Success);
                        }))
                        {
                            continue;
                        }
                        future.Task.Wait();
                        if (r.IsTimeout)
                        {
                            continue;
                        }

                        lock (Raft)
                        {
                            if (this.TrySetTerm(r.Result.Term))
                            {
                                // new term found.
                                Raft.ConvertStateTo(Raft.RaftState.Follower);
                                return;
                            }
                        }

                        switch (r.ResultCode)
                        {
                        case global::Zeze.Raft.InstallSnapshot.ResultCodeNewOffset:
                            break;

                        default:
                            logger.Warn($"InstallSnapshot Break ResultCode={r.ResultCode}");
                            return;
                        }

                        if (r.Result.Offset >= 0)
                        {
                            if (r.Result.Offset > snapshotFile.Length)
                            {
                                logger.Error($"InstallSnapshot.Result.Offset Too Big.{r.Result.Offset}/{snapshotFile.Length}");
                                return; // 中断安装。
                            }
                            offset = r.Result.Offset;
                            snapshotFile.Seek(offset, SeekOrigin.Begin);
                        }
                        break;
                    }
                }
                InstallSuccess = Raft.IsLeader;
                logger.Debug("{0} InstallSnapshot [SUCCESS] Path={1} ToConnector={2}",
                             Raft.Name, path, connector.Name);
            }
            finally
            {
                lock (Raft)
                {
                    connector.InstallSnapshotting = false;
                    InstallSnapshotting.Remove(connector.Name);
                    if (InstallSuccess)
                    {
                        // 安装完成,重新初始化,使得以后的AppendEnties能继续工作。
                        // = FirstIndex + 1,防止Index跳着分配,使用ReadLogStart。
                        var next = ReadLogStart(FirstIndex + 1);
                        connector.NextIndex = next == null ? FirstIndex + 1 : next.Index;
                    }
                }
            }
        }