diff --git a/src/ra_server.erl b/src/ra_server.erl index 83e98808..3f5d1ba2 100644 --- a/src/ra_server.erl +++ b/src/ra_server.erl @@ -919,23 +919,10 @@ 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{term = Term, last_log_index = PeerLastIdx} = PreVote, - #{current_term := CurTerm, - cfg := #cfg{log_id = LogId}} = State) - when Term =:= CurTerm -> - %% This clause is necessary to prevent the liveness issue reported in https://github.com/rabbitmq/ra/issues/439 - {LastIdx, _} = last_idx_term(State), - case PeerLastIdx > LastIdx of - true -> - ?INFO("~ts: candidate pre_vote_rpc with higher last index received ~b -> ~b", - [LogId, LastIdx, PeerLastIdx]), - process_pre_vote(candidate, PreVote, State); - false -> - {candidate, State, []} - end; -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) -> + %% unlink request_vote_rpc, candidate cannot simply reject 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, []}; diff --git a/test/ra_server_SUITE.erl b/test/ra_server_SUITE.erl index b4f15ddf..795d38f8 100644 --- a/test/ra_server_SUITE.erl +++ b/test/ra_server_SUITE.erl @@ -1936,18 +1936,20 @@ candidate_receives_pre_vote(_Config) -> token = Token, machine_version = 0, last_log_index = 3, last_log_term = 5}, - {candidate, #{}, []} + % 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), - % candidate replies `#pre_vote_result{vote_granted=true}` for higher index - {candidate, #{}, - [{reply, #pre_vote_result{token = Token, vote_granted = true}}]} - = ra_server:handle_candidate(PreVoteRpc#pre_vote_rpc{last_log_index = 4}, State), - ok. leader_receives_pre_vote(_Config) ->