Skip to content

Commit

Permalink
allow a node to vote for the current leader, fixes hashicorp#74
Browse files Browse the repository at this point in the history
  • Loading branch information
superfell committed Jan 19, 2016
1 parent b95f335 commit 32051c1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
17 changes: 9 additions & 8 deletions raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -1407,10 +1407,11 @@ func (r *Raft) requestVote(rpc RPC, req *RequestVoteRequest) {
rpc.Respond(resp, rpcErr)
}()

// Check if we have an existing leader
if leader := r.Leader(); leader != "" {
r.logger.Printf("[WARN] raft: Rejecting vote from %v since we have a leader: %v",
r.trans.DecodePeer(req.Candidate), leader)
// Check if we have an existing leader [who's not the candidate]
candidate := r.trans.DecodePeer(req.Candidate)
if leader := r.Leader(); leader != "" && leader != candidate {
r.logger.Printf("[WARN] raft: Rejecting vote request from %v since we have a leader: %v",
candidate, leader)
return
}

Expand Down Expand Up @@ -1452,14 +1453,14 @@ func (r *Raft) requestVote(rpc RPC, req *RequestVoteRequest) {
// Reject if their term is older
lastIdx, lastTerm := r.getLastEntry()
if lastTerm > req.LastLogTerm {
r.logger.Printf("[WARN] raft: Rejecting vote from %v since our last term is greater (%d, %d)",
r.trans.DecodePeer(req.Candidate), lastTerm, req.LastLogTerm)
r.logger.Printf("[WARN] raft: Rejecting vote request from %v since our last term is greater (%d, %d)",
candidate, lastTerm, req.LastLogTerm)
return
}

if lastIdx > req.LastLogIndex {
r.logger.Printf("[WARN] raft: Rejecting vote from %v since our last index is greater (%d, %d)",
r.trans.DecodePeer(req.Candidate), lastIdx, req.LastLogIndex)
r.logger.Printf("[WARN] raft: Rejecting vote request from %v since our last index is greater (%d, %d)",
candidate, lastIdx, req.LastLogIndex)
return
}

Expand Down
44 changes: 42 additions & 2 deletions raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ func (c *cluster) Disconnect(a string) {
}
}

func (c *cluster) IndexOf(r *Raft) int {
for i, n := range c.rafts {
if n == r {
return i
}
}
return -1
}

func (c *cluster) EnsureLeader(t *testing.T, expect string) {
limit := time.Now().Add(400 * time.Millisecond)
CHECK:
Expand Down Expand Up @@ -1589,7 +1598,7 @@ func TestRaft_NotifyCh(t *testing.T) {
if !v {
t.Fatalf("should become leader")
}
case <-time.After(conf.HeartbeatTimeout * 3):
case <-time.After(conf.HeartbeatTimeout * 6):
t.Fatalf("timeout becoming leader")
}

Expand All @@ -1602,7 +1611,38 @@ func TestRaft_NotifyCh(t *testing.T) {
if v {
t.Fatalf("should step down as leader")
}
case <-time.After(conf.HeartbeatTimeout * 3):
case <-time.After(conf.HeartbeatTimeout * 6):
t.Fatalf("timeout becoming leader")
}
}

func TestRaft_Voting(t *testing.T) {
c := MakeCluster(3, t, nil)
defer c.Close()
followers := c.Followers()
ldr := c.Leader()
ldrT := c.trans[c.IndexOf(ldr)]

reqVote := RequestVoteRequest{
Term: 42,
Candidate: ldrT.EncodePeer(ldr.localAddr),
LastLogIndex: ldr.LastIndex(),
LastLogTerm: 1,
}
// a follower that thinks there's a leader should vote for that leader.
var resp RequestVoteResponse
if err := ldrT.RequestVote(followers[0].localAddr, &reqVote, &resp); err != nil {
t.Fatalf("RequestVote RPC failed %v", err)
}
if !resp.Granted {
t.Fatalf("expected vote to be granted, but wasn't %+v", resp)
}
// a follow that thinks there's a leader shouldn't vote for a different candidate
reqVote.Candidate = ldrT.EncodePeer(followers[0].localAddr)
if err := ldrT.RequestVote(followers[1].localAddr, &reqVote, &resp); err != nil {
t.Fatalf("RequestVote RPC failed %v", err)
}
if resp.Granted {
t.Fatalf("expected vote not to be granted, but was %+v", resp)
}
}

0 comments on commit 32051c1

Please sign in to comment.