// lesson: the-problem-and-the-players

The Problem and the Players

A single server that applies commands in order is easy to reason about: it is a state machine. Feed it the same commands in the same order and it always ends up in the same state. The whole trick of fault-tolerant systems is to run several copies of that state machine and keep them in sync โ€” a replicated state machine. If every replica applies the same log of commands in the same order, the replicas are interchangeable, and the service survives the loss of a minority of them.

So the real problem is not replicating the state machine. It is replicating the log. That is what a consensus algorithm does, and Raft (Ongaro & Ousterhout, In Search of an Understandable Consensus Algorithm) is a consensus algorithm designed above all to be understandable. Keep the paper open while you take this course โ€” Figure 2 of the paper is the complete specification, and every challenge here implements a piece of it verbatim. Struct and field names in this course deliberately match the paper (currentTerm, votedFor, prevLogIndex, leaderCommit, โ€ฆ) so the paper reads as your documentation.

Terms: Raft's logical clock

Raft divides time into terms, numbered with consecutive integers. Each term begins with an election; at most one leader can win a given term. Terms act as a logical clock: every message carries the sender's term, and servers use it to detect stale information. Two rules from Figure 2 ("Rules for Servers, All Servers") do most of the work:

  • If a request or response contains a term T > currentTerm: set currentTerm = T and convert to follower.
  • If a message carries a term smaller than currentTerm, it is stale: reject or ignore it (replying with your own term so the sender can update itself).

The three states

At any moment a server is in exactly one of three states (paper ยง5.1):

  • Follower โ€” passive; responds to requests from leaders and candidates.
  • Candidate โ€” trying to get elected leader.
  • Leader โ€” handles all client requests and drives log replication.

Figure 4 of the paper draws the transitions:

// Follower  --times out, starts election-->            Candidate
// Candidate --times out, new election-->               Candidate (again)
// Candidate --receives votes from majority-->          Leader
// Candidate --discovers current leader or new term---> Follower
// Leader    --discovers server with higher term-->     Follower

A follower that hears nothing from a leader for an election timeout assumes the leader is dead: it increments currentTerm, votes for itself, and becomes a candidate. A candidate that gathers votes from a majority of the cluster becomes leader. A candidate that instead receives an AppendEntries request from a legitimate leader (same or higher term) steps back down to follower. And anyone who sees a higher term โ€” leader included โ€” immediately becomes a follower of that term.

Majorities are why Raft works: any two majorities of the same cluster overlap in at least one server, so at most one candidate can win a term, and any elected leader has talked to at least one server that saw previous decisions.

Modeling this deterministically

In this course we never open a socket or start a timer. Time and messages are data: an election timeout is just an event value, an incoming RPC is just a struct. Every function you write is a pure, deterministic step over in-memory state โ€” which is exactly how you want to unit-test a consensus algorithm before you ever wire it to a network.

โ€บ The State Transition Function

25 pts

Implement Step, the Figure 4 transition function. It takes a server's election-relevant state and one event, and returns the new state (it must not matter that the input is passed by value โ€” return the updated copy).

Events model the three stimuli a server's election logic reacts to:

  • EventTimeout โ€” the election timer fired. Term is 0 for this event.
  • EventVote โ€” a RequestVote reply arrived, carrying the replier's Term and whether the vote was Granted.
  • EventAppend โ€” an AppendEntries request arrived from a server claiming to be leader, carrying its Term.

Apply these rules, in this order:

  1. Higher term wins (Figure 2, All Servers): if the event is a message (EventVote or EventAppend) and ev.Term > s.CurrentTerm, set CurrentTerm = ev.Term, become Follower, reset VotedFor to -1 and VotesGranted to 0 โ€” then continue processing the event.
  2. EventTimeout: leaders ignore it (a leader has no election timer). Followers and candidates become Candidate: increment CurrentTerm, set VotedFor = s.ID, set VotesGranted = 1 (you vote for yourself). If that single vote is already a majority (2*VotesGranted > ClusterSize โ€” a one-node cluster), become Leader immediately.
  3. EventVote: only a candidate counts votes, and only replies that are Granted and carry exactly the current term (stale-term replies are ignored). Increment VotesGranted; on reaching a majority, become Leader.
  4. EventAppend: if ev.Term < s.CurrentTerm, ignore it โ€” the sender is a stale leader. Otherwise the sender is the legitimate leader of the current term: a candidate steps down to Follower; a follower stays a follower; the term and VotedFor are unchanged.

Log in to submit a solution and earn points.