A leader can't just assume an entry is safe the instant it appends it to its own log -- if the leader crashes right after, that entry could be lost. Raft's rule: an entry is committed once a MAJORITY of the cluster (leader included) has it replicated. Once that's true, the entry is guaranteed to survive any single-node failure, because any future leader election requires a majority of votes, and at least one voter in that majority must have the entry.
append() is done for you. Implement RaftLog.acknowledge(follower_id, replicated_length): a follower reports it has replicated the leader's first
replicated_length entries.
- Update
match_index[follower_id] = replicated_length. - Recompute
commit_indexas the HIGHEST length that a MAJORITY of the cluster has replicated. The leader always counts as having the fulllen(self.entries); a follower that hasn't acknowledged anything yet counts as having replicated 0. commit_indexmust never move backwards, even if a slower follower's report would otherwise compute a lower value.
Example
log = RaftLog(cluster_size=3) # leader + 2 followers, majority = 2
log.append("cmd1")
log.acknowledge("f1", 1) # leader + f1 = 2 of 3 = majority
log.commit_index # -> 1
Constraints
- "Majority replicated a length" means: sort every node's replicated length
(leader + all followers, unacknowledged followers counted as 0)
descending; the value at index
cluster_size // 2is the highest length at least a majority has reached. (This is the same trick real Raft implementations use -- it avoids checking every possible length one at a time.)
Real-world grounding
- etcd's Raft log replication and commit-index computation:
etcd-io/raft,log.go