diff --git a/raft/raft.go b/raft/raft.go index eb69f903d..8af1ae4eb 100644 --- a/raft/raft.go +++ b/raft/raft.go @@ -265,6 +265,10 @@ func (r *raft) appendEntry(e pb.Entry) { // tickElection is ran by followers and candidates after r.electionTimeout. func (r *raft) tickElection() { + if !r.promotable() { + r.elapsed = 0 + return + } r.elapsed++ // TODO (xiangli): elctionTimeout should be randomized. if r.elapsed > r.electionTimeout { @@ -530,6 +534,13 @@ func (r *raft) delProgress(id int64) { delete(r.prs, id) } +// promotable indicates whether state machine can be promoted to leader, +// which is true when its own id is in progress list. +func (r *raft) promotable() bool { + _, ok := r.prs[r.id] + return ok +} + func (r *raft) loadEnts(ents []pb.Entry) { r.raftLog.load(ents) } diff --git a/raft/raft_test.go b/raft/raft_test.go index 106d4fd34..f343cba65 100644 --- a/raft/raft_test.go +++ b/raft/raft_test.go @@ -1053,6 +1053,28 @@ func TestRemoveNode(t *testing.T) { } } +func TestPromotable(t *testing.T) { + id := int64(1) + tests := []struct { + peers []int64 + wp bool + }{ + {[]int64{1}, true}, + {[]int64{1, 2, 3}, true}, + {[]int64{}, false}, + {[]int64{2, 3}, false}, + } + for i, tt := range tests { + r := &raft{id: id, prs: make(map[int64]*progress)} + for _, id := range tt.peers { + r.prs[id] = &progress{} + } + if g := r.promotable(); g != tt.wp { + t.Errorf("#%d: promotable = %v, want %v", i, g, tt.wp) + } + } +} + func ents(terms ...int64) *raft { ents := []pb.Entry{{}} for _, term := range terms {