// lesson: commitment-and-safety

Commitment and Safety

An entry is committed once it is safe to apply to the state machine — Raft then guarantees it will survive any future leader change. The leader tracks, for every follower, matchIndex: the highest log index known to be replicated on that server. Figure 2's "Rules for Servers, Leaders" gives the commit rule:

If there exists an N such that N > commitIndex, a majority of matchIndex[i] ≥ N, and log[N].term == currentTerm: set commitIndex = N (§5.3, §5.4).

Two of those clauses are obvious — pick something new (N > commitIndex) that a majority stores. The third clause, log[N].term == currentTerm, is the subtle heart of Raft's safety argument.

Why majority replication is not enough (§5.4.2, Figure 8)

Figure 8 of the paper walks through the trap on a five-server cluster, S1–S5. In (a), S1 — leader in term 2 — appends an entry at index 2 but replicates it to only one other server (S2) before crashing: a minority. In (b), S5 wins the next election (term 3, with votes from S3, S4, and itself) and writes a different entry at index 2. S5 crashes too; in (c), S1 restarts and wins election again, this time as leader of term 4 — but it has not accepted any new client command yet, so its log still ends at index 2 with the same old term-2 entry. Coming to power, S1 just resumes normal replication (§5.3): retrying AppendEntries against S3 until the consistency check passes backfills that same old, already-existing entry onto S3 too. Nobody asked for that specifically; it falls out of the ordinary log-repair mechanism a new leader always runs. Now S1's old term-2 entry at index 2 sits on a majority of the cluster (S1, S2, and S3) — but nobody ever committed it. May a leader now count those replicas and consider index 2 committed? No. In (d), S5 — whose log still ends in term 3, higher than S1/S2/S3's term-2 last entry, so it looks "up-to-date" by §5.4.1 even though it is missing S1's index-2 entry entirely — wins a later election from S2, S3, and S4, and overwrites index 2 with its own term-3 entry. If counting replicas had been enough to call index 2 committed back in (c), this would be a lost write: the one unforgivable sin of a consensus algorithm.

The fix: a leader only ever commits by counting replicas for entries from its own current term. Old-term entries are never committed directly. They get committed indirectly: the moment a current-term entry at a later index commits, the Log Matching Property guarantees every earlier entry in that log — including the old-term stragglers — is committed with it.

So in the healthy case the sequence is: leader appends in its own term, replicates, counts a majority, advances commitIndex past everything. In the Figure 8 case the old entry simply waits for the new leader to commit its first own-term entry (real implementations append a no-op at the start of a term for exactly this reason).

Counting the leader itself

The leader is a member of the majority too. In this challenge we sidestep the bookkeeping by passing a matchIndex slice with one element per server in the cluster, leader included (the leader's own element is simply len(log)). A majority means strictly more than half of that slice.

Advance the Commit Index

30 pts

Implement AdvanceCommit. Given the cluster's matchIndex (one element per server, leader included), the leader's log, currentTerm, and the current commitIndex, return the new commit index: the largest N with

  • commitIndex < N <= len(log),
  • matchIndex[i] >= N for a strict majority of servers, and
  • log[N-1].Term == currentTerm (remember: Raft index N lives at log[N-1]).

If no such N exists, return commitIndex unchanged. The function is pure — no mutation, no side effects.

Log in to submit a solution and earn points.