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