Skip to content

Commit 33b56ae

Browse files
Sarah Hassanfacebook-github-bot
Sarah Hassan
authored andcommitted
handle request_vote messages for the witness state
Summary: Add clauses to witness state allowing it to handle request_vote messages. Differential Revision: D53245343 fbshipit-source-id: 6ba577bfbc053a38a5fc975a8b24730ef4af3c52
1 parent c023bc3 commit 33b56ae

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/wa_raft_server.erl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,50 @@ witness({call, From}, ?SNAPSHOT_AVAILABLE_COMMAND(_, #raft_log_pos{index = Snaps
15061506
{keep_state_and_data, {reply, From, {error, rejected}}}
15071507
end;
15081508

1509+
%% [RequestVote] A witness with an unallocated vote should decide if the requesting candidate is eligible to receive
1510+
%% its vote for the current term and affirm or reject accordingly.
1511+
witness(_Type, ?REMOTE(?IDENTITY_REQUIRES_MIGRATION(_, CandidateId) = Candidate, ?REQUEST_VOTE(_ElectionType, CandidateIndex, CandidateTerm)),
1512+
#raft_state{name = Name, log_view = View, current_term = CurrentTerm, voted_for = undefined} = State) ->
1513+
Index = wa_raft_log:last_index(View),
1514+
{ok, Term} = wa_raft_log:term(View, Index),
1515+
% Witnesses should only vote for candidates whose logs are at least as up-to-date as the local log.
1516+
% Logs are ordered in up-to-dateness by the lexicographic order of the {Term, Index} pair of their latest entry. (5.4.1)
1517+
case {CandidateTerm, CandidateIndex} >= {Term, Index} of
1518+
true ->
1519+
?LOG_NOTICE("Server[~0p, term ~0p, witness] decides to vote for candidate ~0p with up-to-date log at ~0p:~0p versus local log at ~0p:~0p.",
1520+
[Name, CurrentTerm, Candidate, CandidateIndex, CandidateTerm, Index, Term], #{domain => [whatsapp, wa_raft]}),
1521+
NewState = State#raft_state{voted_for = CandidateId},
1522+
% Persist the vote to stable storage before responding to the vote request. (Fig. 2)
1523+
wa_raft_durable_state:store(NewState),
1524+
send_rpc(Candidate, ?VOTE(true), State),
1525+
{keep_state, NewState};
1526+
false ->
1527+
?LOG_NOTICE("Server[~0p, term ~0p, witness] refuses to vote for candidate ~0p with outdated log at ~0p:~0p versus local log at ~0p:~0p.",
1528+
[Name, CurrentTerm, Candidate, CandidateIndex, CandidateTerm, Index, Term], #{domain => [whatsapp, wa_raft]}),
1529+
send_rpc(Candidate, ?VOTE(false), State),
1530+
keep_state_and_data
1531+
end;
1532+
%% [RequestVote] A witness should affirm any vote requests for the candidate it already voted for in the current term.
1533+
witness(_Type, ?REMOTE(?IDENTITY_REQUIRES_MIGRATION(_, CandidateId) = Candidate, ?REQUEST_VOTE(_ElectionType, _CandidateIndex, _CandidateTerm)),
1534+
#raft_state{name = Name, current_term = CurrentTerm, voted_for = CandidateId} = State) ->
1535+
?LOG_NOTICE("Server[~0p, term ~0p, witness] repeating prior vote for candidate ~0p.",
1536+
[Name, CurrentTerm, Candidate], #{domain => [whatsapp, wa_raft]}),
1537+
send_rpc(Candidate, ?VOTE(true), State),
1538+
keep_state_and_data;
1539+
%% [RequestVote] A witness should reject any vote requests for the candidate it did not vote for in the current term.
1540+
witness(_Type, ?REMOTE(Candidate, ?REQUEST_VOTE(_ElectionType, _CandidateIndex, _CandidateTerm)),
1541+
#raft_state{name = Name, current_term = CurrentTerm, voted_for = VotedFor} = State) ->
1542+
?LOG_NOTICE("Server[~0p, term ~0p, witness] refusing to vote for candidate ~0p after previously voting for candidate ~0p in the current term.",
1543+
[Name, CurrentTerm, Candidate, VotedFor], #{domain => [whatsapp, wa_raft]}),
1544+
send_rpc(Candidate, ?VOTE(false), State),
1545+
keep_state_and_data;
1546+
1547+
%% [Vote] A witness should ignore any votes because its not eligible for leadership
1548+
witness(_Type, ?REMOTE(Sender, ?VOTE(Voted)), #raft_state{name = Name, current_term = CurrentTerm}) ->
1549+
?LOG_WARNING("Server[~0p, term ~0p, witness] got unexecpted vote ~p from ~p.",
1550+
[Name, CurrentTerm, Voted, Sender], #{domain => [whatsapp, wa_raft]}),
1551+
keep_state_and_data;
1552+
15091553
%% [Witness] Witness receives RAFT command
15101554
witness(Type, ?RAFT_COMMAND(_COMMAND, _Payload) = Event, State) ->
15111555
command(?FUNCTION_NAME, Type, Event, State);

0 commit comments

Comments
 (0)