Skip to content

Commit

Permalink
Delay the next campaign if the node lost the vote
Browse files Browse the repository at this point in the history
Delay the next campaign if the node lost the vote. It's
highly likely it will also lose next campaign, so it makes
more sense to prioritize campaigns by other nodes within
the current term.

Signed-off-by: Benjamin Wang <[email protected]>
  • Loading branch information
ahrtr committed Feb 22, 2024
1 parent d475d7e commit 34ffcfd
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
7 changes: 7 additions & 0 deletions raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,13 @@ func stepCandidate(r *raft, m pb.Message) error {
// pb.MsgPreVoteResp contains future term of pre-candidate
// m.Term > r.Term; reuse r.Term
r.becomeFollower(r.Term, None)
// Delay the next campaign if the node lost the vote. It's
// highly likely it will also lose next campaign, so it makes
// more sense to prioritize campaigns by other nodes within
// the current term.
if myVoteRespType == pb.MsgVoteResp {
r.randomizedElectionTimeout += r.electionTimeout
}
}
case pb.MsgTimeoutNow:
r.logger.Debugf("%x [term %d state %v] ignored MsgTimeoutNow from %x", r.id, r.Term, r.state, m.From)
Expand Down
30 changes: 30 additions & 0 deletions raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,36 @@ func TestPastElectionTimeout(t *testing.T) {
}
}

func TestRandomizedElectionTimeoutOnLostVote(t *testing.T) {
storage := newTestMemoryStorage(withPeers(1, 2, 3))
storage.Append(index(1).terms(1, 2, 3, 4, 5))
r := newTestRaft(1, 10, 1, storage)

term, index := r.raftLog.lastEntryID().term, r.raftLog.lastEntryID().index
r.Term = term

r.becomeCandidate()
msgVote := pb.Message{
From: 1,
To: 2,
Type: pb.MsgVote,
Term: term + 1,
LogTerm: index,
Index: 42,
}
r.stepOrSend([]pb.Message{msgVote})

// The MsgVote is rejected by r2
err := r.Step(pb.Message{From: 2, To: 1, Term: term + 1, Type: pb.MsgVoteResp, Reject: true})
require.NoError(t, err)
require.Less(t, r.randomizedElectionTimeout, r.electionTimeout*2)

// The MsgVote is rejected by r3
err = r.Step(pb.Message{From: 3, To: 1, Term: term + 1, Type: pb.MsgVoteResp, Reject: true})
require.NoError(t, err)
require.GreaterOrEqual(t, r.randomizedElectionTimeout, r.electionTimeout*2)
}

// TestStepIgnoreOldTermMsg to ensure that the Step function ignores the message
// from old term and does not pass it to the actual stepX function.
func TestStepIgnoreOldTermMsg(t *testing.T) {
Expand Down

0 comments on commit 34ffcfd

Please sign in to comment.