TLA+
------------------------------- MODULE Raft -------------------------------
EXTENDS Naturals, FiniteSets, Sequences, TLC
CONSTANTS Server, Value, Follower, Candidate, Leader, Nil,
RequestVoteRequest, RequestVoteResponse, AppendEntriesRequest,
AppendEntriesResponse
VARIABLES messages, elections, allLogs, currentTerm, state, votedFor, log,
commitIndex, votesResponded, votesGranted, voterLog, nextIndex, matchIndex
leaderVars == <<nextIndex, matchIndex, elections>>
logVars == <<log, commitIndex>>
candidateVars == <<votesResponded, votesGranted, voterLog>>
serverVars == <<currentTerm, state, votedFor>>
vars == <<messages, allLogs, serverVars, candidateVars, leaderVars, logVars>>
Quorum == {
i \in SUBSET Server: Cardinality(i)*2 > Cardinality(Server)}
LastTerm(xlog) == IF Len(xlog) # 0 THEN xlog[Len(xlog)].term ELSE 0
WithMessage(m, msgs) ==
IF m \in DOMAIN msgs THEN
[msgs EXCEPT ![m] = msgs[m] + 1]
ELSE
msgs @@ (m :> 1)
WithoutMessage(m, msgs) ==
IF m \in DOMAIN msgs THEN
[msgs EXCEPT ![m] = msgs[m] - 1]
ELSE
msgs
Send(m) == messages' = WithMessage(m, messages)
Discard(m) == messages' = WithoutMessage(m, messages)
Reply(response, request) ==
messages' = WithoutMessage(request, WithMessage(response, messages))
Min(m) == CHOOSE x \in m: \A y \in m: y >= x
Max(m) == CHOOSE x \in m: \A y \in m: y <= x
----
InitHistoryVars ==
/\ elections = {
}
/\ allLogs = {
}
/\ voterLog = [i \in Server |-> [j \in {
} |-> <<>> ]]
InitServerVars ==
/\ currentTerm = [i \in Server |-> 1]
/\ state = [i \in Server |-> Follower]
/\ votedFor = [i \in Server |-> Nil]
InitCandidateVars ==
/\ votesResponded = [i \in Server |-> {
}]
/\ votesGranted = [i \in Server |-> {
}]
InitLeaderVars ==
/\ nextIndex = [i \in Server |-> [j \in Server |-> 1]]
/\ matchIndex = [i \in Server |-> [j \in Server |-> 0]]
InitLogVars ==
/\ log = [i \in Server |-> <<>>]
/\ commitIndex = [i \in Server |-> 0]
Init ==
/\ messages = [ m \in {
} |-> 0 ]
/\ InitHistoryVars
/\ InitServerVars
/\ InitCandidateVars
/\ InitLeaderVars
/\ InitLogVars
Restart(i) ==
/\ state' = [state EXCEPT ![i] = Follower]
/\ votesResponded' = [votesResponded EXCEPT ![i] = {
}]
/\ votesGranted' = [votesGranted EXCEPT ![i] = {
}]
/\ voterLog' = [voterLog EXCEPT ![i] = [j \in {
} |-> <<>>]]
/\ nextIndex' = [nextIndex EXCEPT ![i] = [j \in Server |-> 1]]
/\ matchIndex' = [matchIndex EXCEPT ![i] = [j \in Server |-> 0]]
/\ commitIndex' = [commitIndex EXCEPT ![i] = 0]
/\ UNCHANGED <<messages, currentTerm, votedFor, log, elections>>
Timeout(i) ==
/\ state[i] \in {
Follower, Candidate}
/\ state' = [state EXCEPT ![i] = Candidate]
/\ currentTerm' = [currentTerm EXCEPT ![i] = @ + 1]
/\ votedFor' = [votedFor EXCEPT ![i] = Nil]
/\ votesResponded' = [votesResponded EXCEPT ![i