@@ -291,10 +291,11 @@ func (r *Raft) runCandidate() {
291
291
var voteCh <- chan * voteResult
292
292
var prevoteCh <- chan * preVoteResult
293
293
294
- // check if the transport support prevote requests
295
- _ , ok := r .trans .(WithPreVote )
294
+ // check if pre-vote is active and that this is not a leader transfer
296
295
297
- if r .preVote && ok {
296
+ // Leader transfer do not perform prevote by design, as the selected server is very likely to be fit
297
+ // and an election will happen in all cases.
298
+ if r .preVote && ! r .candidateFromLeadershipTransfer .Load () {
298
299
prevoteCh = r .preElectSelf ()
299
300
} else {
300
301
voteCh = r .electSelf ()
@@ -327,10 +328,10 @@ func (r *Raft) runCandidate() {
327
328
case preVote := <- prevoteCh :
328
329
// This a pre-vote case it should trigger a "real" election if the pre-vote is won.
329
330
r .mainThreadSaturation .working ()
330
- r .logger .Debug ("got a prevote!! " , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
331
+ r .logger .Debug ("pre-vote received " , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
331
332
// Check if the term is greater than ours, bail
332
333
if preVote .Term > term {
333
- r .logger .Debug ("newer term discovered on pre-preVote, fallback to follower" , "term" , preVote .Term )
334
+ r .logger .Debug ("pre-vote denied: found newer term, falling back to follower" , "term" , preVote .Term )
334
335
r .setState (Follower )
335
336
r .setCurrentTerm (preVote .Term )
336
337
return
@@ -339,15 +340,15 @@ func (r *Raft) runCandidate() {
339
340
// Check if the preVote is granted
340
341
if preVote .Granted {
341
342
preVoteGrantedVotes ++
342
- r .logger .Debug ("prevote granted" , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
343
+ r .logger .Debug ("pre-vote granted" , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
343
344
} else {
344
345
preVoteRefusedVotes ++
345
- r .logger .Debug ("prevote refused " , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
346
+ r .logger .Debug ("pre-vote denied " , "from" , preVote .voterID , "term" , preVote .Term , "tally" , preVoteGrantedVotes )
346
347
}
347
348
348
349
// Check if we've won the pre-vote and proceed to election if so
349
350
if preVoteGrantedVotes >= votesNeeded {
350
- r .logger .Info ("pre election won " , "term" , preVote .Term , "tally" , preVoteGrantedVotes , "votesNeeded" , votesNeeded - 1 )
351
+ r .logger .Info ("pre-vote successful, starting election " , "term" , preVote .Term , "tally" , preVoteGrantedVotes , "votesNeeded" , votesNeeded - 1 )
351
352
preVoteGrantedVotes = 0
352
353
preVoteRefusedVotes = 0
353
354
electionTimer = randomTimeout (electionTimeout )
@@ -357,7 +358,7 @@ func (r *Raft) runCandidate() {
357
358
// Check if we've lost the pre-vote and wait for the election to timeout so we can do another time of
358
359
// prevote.
359
360
if preVoteRefusedVotes >= votesNeeded {
360
- r .logger .Info ("pre election lost, wait for election to timeout" , "term" , preVote .Term , "tally" , preVoteGrantedVotes , "votesNeeded" , votesNeeded - 1 )
361
+ r .logger .Info ("pre-vote campaign failed, waiting for election timeout" , "term" , preVote .Term , "tally" , preVoteGrantedVotes , "votesNeeded" , votesNeeded - 1 )
361
362
}
362
363
case vote := <- voteCh :
363
364
r .mainThreadSaturation .working ()
@@ -369,7 +370,7 @@ func (r *Raft) runCandidate() {
369
370
return
370
371
}
371
372
372
- // Check if the preVote is granted
373
+ // Check if the vote is granted
373
374
if vote .Granted {
374
375
grantedVotes ++
375
376
r .logger .Debug ("vote granted" , "from" , vote .voterID , "term" , vote .Term , "tally" , grantedVotes )
@@ -1721,7 +1722,7 @@ func (r *Raft) requestVote(rpc RPC, req *RequestVoteRequest) {
1721
1722
return
1722
1723
}
1723
1724
1724
- // Persist a vote for safety\
1725
+ // Persist a vote for safety
1725
1726
if err := r .persistVote (req .Term , candidateBytes ); err != nil {
1726
1727
r .logger .Error ("failed to persist vote" , "error" , err )
1727
1728
return
@@ -1731,7 +1732,7 @@ func (r *Raft) requestVote(rpc RPC, req *RequestVoteRequest) {
1731
1732
r .setLastContact ()
1732
1733
}
1733
1734
1734
- // requestPreVote is invoked when we get a request vote RPC call.
1735
+ // requestPreVote is invoked when we get a request Pre-Vote RPC call.
1735
1736
func (r * Raft ) requestPreVote (rpc RPC , req * RequestPreVoteRequest ) {
1736
1737
defer metrics .MeasureSince ([]string {"raft" , "rpc" , "requestVote" }, time .Now ())
1737
1738
r .observe (* req )
@@ -1747,12 +1748,6 @@ func (r *Raft) requestPreVote(rpc RPC, req *RequestPreVoteRequest) {
1747
1748
rpc .Respond (resp , rpcErr )
1748
1749
}()
1749
1750
1750
- // Version 0 servers will panic unless the peers is present. It's only
1751
- // used on them to produce a warning message.
1752
- if r .protocolVersion < 2 {
1753
- resp .Peers = encodePeers (r .configurations .latest , r .trans )
1754
- }
1755
-
1756
1751
// Check if we have an existing leader [who's not the candidate] and also
1757
1752
// check the LeadershipTransfer flag is set. Usually votes are rejected if
1758
1753
// there is a known leader. But if the leader initiated a leadership transfer,
@@ -1768,7 +1763,7 @@ func (r *Raft) requestPreVote(rpc RPC, req *RequestPreVoteRequest) {
1768
1763
return
1769
1764
}
1770
1765
1771
- if leaderAddr , leaderID := r .LeaderWithID (); leaderAddr != "" && leaderAddr != candidate && ! req . LeadershipTransfer {
1766
+ if leaderAddr , leaderID := r .LeaderWithID (); leaderAddr != "" && leaderAddr != candidate {
1772
1767
r .logger .Warn ("rejecting pre-vote request since we have a leader" ,
1773
1768
"from" , candidate ,
1774
1769
"leader" , leaderAddr ,
@@ -1781,18 +1776,14 @@ func (r *Raft) requestPreVote(rpc RPC, req *RequestPreVoteRequest) {
1781
1776
return
1782
1777
}
1783
1778
1784
- // Increase the term if we see a newer one
1785
1779
if req .Term > r .getCurrentTerm () {
1786
1780
// continue processing here to possibly grant the pre-vote as in a "real" vote this will transition us to follower
1787
1781
r .logger .Debug ("received a requestPreVote with a newer term, grant the pre-vote" )
1788
1782
resp .Term = req .Term
1789
1783
}
1790
1784
1791
- // if we get a request for vote from a nonVoter and the request term is higher,
1792
- // step down and update term, but reject the vote request
1785
+ // if we get a request for a pre-vote from a nonVoter and the request term is higher, do not grant the Pre-Vote
1793
1786
// This could happen when a node, previously voter, is converted to non-voter
1794
- // The reason we need to step in is to permit to the cluster to make progress in such a scenario
1795
- // More details about that in https://github.com/hashicorp/raft/pull/526
1796
1787
if len (r .configurations .latest .Servers ) > 0 && ! hasVote (r .configurations .latest , candidateID ) {
1797
1788
r .logger .Warn ("rejecting pre-vote request since node is not a voter" , "from" , candidate )
1798
1789
return
@@ -1801,15 +1792,15 @@ func (r *Raft) requestPreVote(rpc RPC, req *RequestPreVoteRequest) {
1801
1792
// Reject if their term is older
1802
1793
lastIdx , lastTerm := r .getLastEntry ()
1803
1794
if lastTerm > req .LastLogTerm {
1804
- r .logger .Warn ("rejecting vote request since our last term is greater" ,
1795
+ r .logger .Warn ("rejecting pre- vote request since our last term is greater" ,
1805
1796
"candidate" , candidate ,
1806
1797
"last-term" , lastTerm ,
1807
1798
"last-candidate-term" , req .LastLogTerm )
1808
1799
return
1809
1800
}
1810
1801
1811
1802
if lastTerm == req .LastLogTerm && lastIdx > req .LastLogIndex {
1812
- r .logger .Warn ("rejecting vote request since our last index is greater" ,
1803
+ r .logger .Warn ("rejecting pre- vote request since our last index is greater" ,
1813
1804
"candidate" , candidate ,
1814
1805
"last-index" , lastIdx ,
1815
1806
"last-candidate-index" , req .LastLogIndex )
@@ -2055,10 +2046,11 @@ func (r *Raft) electSelf() <-chan *voteResult {
2055
2046
return respCh
2056
2047
}
2057
2048
2058
- // preElectSelf is used to send a RequestVote RPC to all peers, and vote for
2059
- // ourself. This has the side affecting of incrementing the current term. The
2049
+ // preElectSelf is used to send a RequestPreVote RPC to all peers, and vote for
2050
+ // ourself. This will not increment the current term. The
2060
2051
// response channel returned is used to wait for all the responses (including a
2061
- // vote for ourself). This must only be called from the main thread.
2052
+ // vote for ourself).
2053
+ // This must only be called from the main thread.
2062
2054
func (r * Raft ) preElectSelf () <- chan * preVoteResult {
2063
2055
// Create a response channel
2064
2056
respCh := make (chan * preVoteResult , len (r .configurations .latest .Servers ))
@@ -2072,10 +2064,9 @@ func (r *Raft) preElectSelf() <-chan *preVoteResult {
2072
2064
RPCHeader : r .getRPCHeader (),
2073
2065
Term : newTerm ,
2074
2066
// this is needed for retro compatibility, before RPCHeader.Addr was added
2075
- Candidate : r .trans .EncodePeer (r .localID , r .localAddr ),
2076
- LastLogIndex : lastIdx ,
2077
- LastLogTerm : lastTerm ,
2078
- LeadershipTransfer : r .candidateFromLeadershipTransfer .Load (),
2067
+ Candidate : r .trans .EncodePeer (r .localID , r .localAddr ),
2068
+ LastLogIndex : lastIdx ,
2069
+ LastLogTerm : lastTerm ,
2079
2070
}
2080
2071
2081
2072
// Construct a function to ask for a vote
@@ -2113,8 +2104,8 @@ func (r *Raft) preElectSelf() <-chan *preVoteResult {
2113
2104
if server .Suffrage == Voter {
2114
2105
if server .ID == r .localID {
2115
2106
r .logger .Debug ("pre-voting for self" , "term" , req .Term , "id" , r .localID )
2116
- // Persist a vote for ourselves
2117
- // Include our own vote
2107
+
2108
+ // cast a pre- vote for our self
2118
2109
respCh <- & preVoteResult {
2119
2110
RequestPreVoteResponse : RequestPreVoteResponse {
2120
2111
RPCHeader : r .getRPCHeader (),
0 commit comments