// add log entries according to the ApplyMsg struct type LogEntry struct { Term int CommandValid bool Command interface{} }
// add the fields about log: // PrevLogIndex and PrevLogTerm is used to match the log prefix // Entries is used to append when matched // LeaderCommit tells the follower to update its own commitIndex type AppendEntriesArgs struct { Term int LeaderId int
PrevLogIndex int PrevLogTerm int Entries []LogEntry }
type AppendEntriesReply struct { Term int Success bool }
Raft 结构体
定义了 LogEntry 之后,完善下 raft struct 中相关字段:
1 2 3 4 5 6 7
// log in Peer's local log []LogEntry
// only used when it is Leader, // log view for each peer nextIndex []int matchIndex []int
所谓日志匹配:就是相同 Index 的地方,Term 相同;即 index 和 term 能唯一确定一条日志,这是因为,Raft 算法保证一个 Term 中最多有(也可能没有)一个 Leader,然后只有该 Leader 能确定日志顺序且同步日志。这样一来,Term 单调递增,每个 Term 只有一个 Leader,则该 Leader 能唯一确定该 Term 内的日志顺序。
rf.mu.Lock() defer rf.mu.Unlock() if !ok { LOG(rf.me, rf.currentTerm, DLog, "-> S%d, Lost or crashed", peer) return }
// align the term if reply.Term > rf.currentTerm { rf.becomeFollowerLocked(reply.Term) return }
// probe the lower index if the prev log not matched if !reply.Success { idx := rf.nextIndex[peer] - 1 term := rf.log[idx].Term for idx > 0 && rf.log[idx].Term == term { idx-- } rf.nextIndex[peer] = idx + 1 LOG(rf.me, rf.currentTerm, DLog, "Log not matched in %d, Update next=%d", args.PrevLogIndex, rf.nextIndex[peer]) return }
// update the match/next index if log appended successfully rf.matchIndex[peer] = args.PrevLogIndex + len(args.Entries) rf.nextIndex[peer] = rf.matchIndex[peer] + 1 // TODO: need compute the new commitIndex here, // but we leave it to the other chapter }
rf.mu.Lock() defer rf.mu.Unlock()
if rf.contextLostLocked(Leader, term) { LOG(rf.me, rf.currentTerm, DLog, "Lost Leader[%d] to %s[T%d]", term, rf.role, rf.currentTerm) returnfalse }