Skip to content

Commit

Permalink
Merge pull request #442 from sile/fix-issue-439
Browse files Browse the repository at this point in the history
Fix a bug where the leader is never elected even if the majority of the members are alive.
  • Loading branch information
kjnilsson authored Jun 5, 2024
2 parents bdf8349 + d50203f commit d128c81
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
8 changes: 5 additions & 3 deletions src/ra_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -919,9 +919,11 @@ handle_candidate(#pre_vote_rpc{term = Term} = Msg,
handle_candidate(#request_vote_rpc{}, State = #{current_term := Term}) ->
Reply = #request_vote_result{term = Term, vote_granted = false},
{candidate, State, [{reply, Reply}]};
handle_candidate(#pre_vote_rpc{}, State) ->
%% just ignore pre_votes that aren't of a higher term
{candidate, State, []};
handle_candidate(#pre_vote_rpc{} = PreVote, State) ->
%% unlike request_vote_rpc, a candidate cannot simply reject
%% a pre_vote_rpc that does not have a higher term
%% (see https://github.com/rabbitmq/ra/issues/439 for the detail)
process_pre_vote(candidate, PreVote, State);
handle_candidate(#request_vote_result{}, State) ->
%% handle to avoid logging as unhandled
{candidate, State, []};
Expand Down
25 changes: 25 additions & 0 deletions test/ra_server_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ all() ->
higher_term_detected,
pre_vote_election,
pre_vote_election_reverts,
candidate_receives_pre_vote,
leader_receives_pre_vote,
candidate_election,
is_new,
Expand Down Expand Up @@ -1927,6 +1928,30 @@ pre_vote_election_reverts(_Config) ->
= ra_server:handle_pre_vote(ISR, State),
ok.

candidate_receives_pre_vote(_Config) ->
% candidate ignores an pre_vote_rpc with lower term and lower index
Token = make_ref(),
State = (base_state(5, ?FUNCTION_NAME))#{votes => 1},
PreVoteRpc = #pre_vote_rpc{term = 5, candidate_id = ?N1,
token = Token,
machine_version = 0,
last_log_index = 3, last_log_term = 5},
% candidate replies `#pre_vote_result{vote_granted=true}` for not lower index
{candidate, #{},
[{reply, #pre_vote_result{token = Token, vote_granted = true}}]}
= ra_server:handle_candidate(PreVoteRpc, State),

% candidate replies `#pre_vote_result{vote_granted=false}` for lower index
{candidate, #{},
[{reply, #pre_vote_result{token = Token, vote_granted = false}}]}
= ra_server:handle_candidate(PreVoteRpc#pre_vote_rpc{last_log_index = 2}, State),

% candidate abdicates for higher term
{follower, #{current_term := 6}, _}
= ra_server:handle_candidate(PreVoteRpc#pre_vote_rpc{term = 6}, State),

ok.

leader_receives_pre_vote(_Config) ->
% leader should emit rpcs to all nodes immediately upon receiving
% an pre_vote_rpc to put upstart followers back in their place
Expand Down

0 comments on commit d128c81

Please sign in to comment.