public void EndReceiveInstallSnapshot(FileStream s, InstallSnapshot r) { lock (Raft) { // 6. If existing log entry has same index and term as snapshot’s // last included entry, retain log entries following it and reply var last = ReadLog(r.Argument.LastIncludedIndex); if (null != last && last.Term == r.Argument.LastIncludedTerm) { // 这里全部保留更简单吧,否则如果没有applied,那不就糟了吗? // RemoveLogReverse(r.Argument.LastIncludedIndex - 1); return; } // 7. Discard the entire log // 整个删除,那么下一次AppendEnties又会找不到prev。不就xxx了吗? // 我的想法是,InstallSnapshot 最后一个 trunk 带上 LastIncludedLog, // 接收者清除log,并把这条日志插入(这个和系统初始化时插入的Index=0的日志道理差不多)。 // 【除了快照最后包含的日志,其他都删除。】 var lastIncludedLog = RaftLog.Decode(r.Argument.LastIncludedLog, Raft.StateMachine.LogFactory); SaveLog(lastIncludedLog); // follower 没有并发请求需要处理,在锁内删除。 RemoveLogReverse(lastIncludedLog.Index - 1, FirstIndex); RemoveLogAndCancelStart(lastIncludedLog.Index + 1, LastIndex); LastIndex = lastIncludedLog.Index; FirstIndex = lastIncludedLog.Index; CommitIndex = FirstIndex; LastApplied = FirstIndex; // 8. Reset state machine using snapshot contents (and load // snapshot’s cluster configuration) Raft.StateMachine.LoadFromSnapshot(s.Name); logger.Debug("{0} EndReceiveInstallSnapshot Path={1}", Raft.Name, s.Name); } }
internal int FollowerOnAppendEntries(AppendEntries r) { LeaderActiveTime = Zeze.Util.Time.NowUnixMillis; r.Result.Term = Term; r.Result.Success = false; // set default false if (r.Argument.Term < Term) { // 1. Reply false if term < currentTerm (§5.1) r.SendResult(); return(Procedure.LogicError); } var prevLog = ReadLog(r.Argument.PrevLogIndex); if (prevLog == null || prevLog.Term != r.Argument.PrevLogTerm) { // 2. Reply false if log doesn’t contain an entry // at prevLogIndex whose term matches prevLogTerm(§5.3) r.SendResult(); return(Procedure.LogicError); } foreach (var raftLogData in r.Argument.Entries) { var copyLog = RaftLog.Decode(raftLogData, Raft.StateMachine.LogFactory); var conflictCheck = ReadLog(copyLog.Index); if (null != conflictCheck) { if (conflictCheck.Term != copyLog.Term) { // 3. If an existing entry conflicts // with a new one (same index but different terms), // delete the existing entry and all that follow it(§5.3) // raft.pdf 5.3 RemoveLogAndCancelStart(conflictCheck.Index, LastIndex); LastIndex = prevLog.Index; } } else { // 4. Append any new entries not already in the log SaveLog(copyLog); } // 复用这个变量。当冲突需要删除时,精确指到前一个日志。 prevLog = copyLog; } // 5. If leaderCommit > commitIndex, // set commitIndex = min(leaderCommit, index of last new entry) if (r.Argument.LeaderCommit > CommitIndex) { CommitIndex = Math.Min(r.Argument.LeaderCommit, LastRaftLog().Index); TryApply(ReadLog(CommitIndex)); } r.Result.Success = true; logger.Debug("{0}: {1}", Raft.Name, r); r.SendResultCode(0); return(Procedure.Success); }
private RaftLog ReadLog(long index) { var key = ByteBuffer.Allocate(); key.WriteLong8(index); var value = Logs.Get(key.Bytes, key.Size); if (null == value) { return(null); } return(RaftLog.Decode(new Binary(value), Raft.StateMachine.LogFactory)); }
public LogSequence(Raft raft) { Raft = raft; var options = new DbOptions().SetCreateIfMissing(true); Rafts = RocksDb.Open(options, Path.Combine(Raft.RaftConfig.DbHome, "rafts")); { // Read Term var termKey = ByteBuffer.Allocate(); termKey.WriteInt(0); RaftsTermKey = termKey.Copy(); var termValue = Rafts.Get(RaftsTermKey); if (null != termValue) { var bb = ByteBuffer.Wrap(termValue); Term = bb.ReadLong(); } else { Term = 0; } // Read VoteFor var voteForKey = ByteBuffer.Allocate(); voteForKey.WriteInt(1); RaftsVoteForKey = voteForKey.Copy(); var voteForvalue = Rafts.Get(RaftsVoteForKey); if (null != voteForvalue) { var bb = ByteBuffer.Wrap(voteForvalue); VoteFor = bb.ReadString(); } else { VoteFor = string.Empty; } } Logs = RocksDb.Open(options, Path.Combine(Raft.RaftConfig.DbHome, "logs")); { // Read Last Log Index using var itLast = Logs.NewIterator(); itLast.SeekToLast(); if (itLast.Valid()) { LastIndex = RaftLog.Decode( new Binary(itLast.Value()), Raft.StateMachine.LogFactory ).Index; } else { // empty. add one for prev. SaveLog(new RaftLog(Term, 0, new HeartbeatLog())); LastIndex = 0; } using var itFirst = Logs.NewIterator(); itFirst.SeekToFirst(); FirstIndex = RaftLog.Decode( new Binary(itFirst.Value()), Raft.StateMachine.LogFactory ).Index; // 【注意】snapshot 以后 FirstIndex 会推进,不再是从0开始。 LastApplied = FirstIndex; CommitIndex = FirstIndex; } }