Skip to content

Commit

Permalink
Merge pull request #8346 from javaforfun/shawnsli/reset-votes-when-be…
Browse files Browse the repository at this point in the history
…come-pre-candidate

raft: reset votes when becomePreCandidate
  • Loading branch information
xiang90 authored Aug 3, 2017
2 parents e77ecb5 + 42cc64a commit 033c0cb
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
1 change: 1 addition & 0 deletions raft/raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ func (r *raft) becomePreCandidate() {
// but doesn't change anything else. In particular it does not increase
// r.Term or change r.Vote.
r.step = stepCandidate
r.votes = make(map[uint64]bool)
r.tick = r.tickElection
r.state = StatePreCandidate
r.logger.Infof("%x became pre-candidate at term %d", r.id, r.Term)
Expand Down
77 changes: 77 additions & 0 deletions raft/raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3209,6 +3209,83 @@ func TestNodeWithSmallerTermCanCompleteElection(t *testing.T) {
}
}

// TestPreVoteWithSplitVote verifies that after split vote, cluster can complete
// election in next round.
func TestPreVoteWithSplitVote(t *testing.T) {
n1 := newTestRaft(1, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
n2 := newTestRaft(2, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
n3 := newTestRaft(3, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())

n1.becomeFollower(1, None)
n2.becomeFollower(1, None)
n3.becomeFollower(1, None)

n1.preVote = true
n2.preVote = true
n3.preVote = true

nt := newNetwork(n1, n2, n3)
nt.send(pb.Message{From: 1, To: 1, Type: pb.MsgHup})

// simulate leader down. followers start split vote.
nt.isolate(1)
nt.send([]pb.Message{
{From: 2, To: 2, Type: pb.MsgHup},
{From: 3, To: 3, Type: pb.MsgHup},
}...)

// check whether the term values are expected
// n2.Term == 3
// n3.Term == 3
sm := nt.peers[2].(*raft)
if sm.Term != 3 {
t.Errorf("peer 2 term: %d, want %d", sm.Term, 3)
}
sm = nt.peers[3].(*raft)
if sm.Term != 3 {
t.Errorf("peer 3 term: %d, want %d", sm.Term, 3)
}

// check state
// n2 == candidate
// n3 == candidate
sm = nt.peers[2].(*raft)
if sm.state != StateCandidate {
t.Errorf("peer 2 state: %s, want %s", sm.state, StateCandidate)
}
sm = nt.peers[3].(*raft)
if sm.state != StateCandidate {
t.Errorf("peer 3 state: %s, want %s", sm.state, StateCandidate)
}

// node 2 election timeout first
nt.send(pb.Message{From: 2, To: 2, Type: pb.MsgHup})

// check whether the term values are expected
// n2.Term == 4
// n3.Term == 4
sm = nt.peers[2].(*raft)
if sm.Term != 4 {
t.Errorf("peer 2 term: %d, want %d", sm.Term, 4)
}
sm = nt.peers[3].(*raft)
if sm.Term != 4 {
t.Errorf("peer 3 term: %d, want %d", sm.Term, 4)
}

// check state
// n2 == leader
// n3 == follower
sm = nt.peers[2].(*raft)
if sm.state != StateLeader {
t.Errorf("peer 2 state: %s, want %s", sm.state, StateLeader)
}
sm = nt.peers[3].(*raft)
if sm.state != StateFollower {
t.Errorf("peer 3 state: %s, want %s", sm.state, StateFollower)
}
}

func entsWithConfig(configFunc func(*Config), terms ...uint64) *raft {
storage := NewMemoryStorage()
for i, term := range terms {
Expand Down

0 comments on commit 033c0cb

Please sign in to comment.