Created
August 12, 2022 16:22
-
-
Save BruceChen7/bece148c2774dd6b31a5bf6c9b42649d to your computer and use it in GitHub Desktop.
#golang#raft#leader#network
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func (r *Raft) requestVote(rpc RPC, req *RequestVoteRequest) { | |
defer metrics.MeasureSince([]string{"raft", "rpc", "requestVote"}, time.Now()) | |
r.observe(*req) | |
// Setup a response | |
resp := &RequestVoteResponse{ | |
RPCHeader: r.getRPCHeader(), | |
// 返回自己节点的任期 | |
Term: r.getCurrentTerm(), | |
Granted: false, | |
} | |
var rpcErr error | |
defer func() { | |
rpc.Respond(resp, rpcErr) | |
}() | |
// Version 0 servers will panic unless the peers is present. It's only | |
// used on them to produce a warning message. | |
if r.protocolVersion < 2 { | |
resp.Peers = encodePeers(r.configurations.latest, r.trans) | |
} | |
// Check if we have an existing leader [who's not the candidate] and also | |
// check the LeadershipTransfer flag is set. Usually votes are rejected if | |
// there is a known leader. But if the leader initiated a leadership transfer, | |
// vote! | |
candidate := r.trans.DecodePeer(req.Candidate) | |
// 获取本节点认为的leader | |
// 不是处于leadershipTransfer | |
if leader := r.Leader(); leader != "" && leader != candidate && !req.LeadershipTransfer { | |
r.logger.Warn("rejecting vote request since we have a leader", | |
"from", candidate, | |
"leader", leader) | |
return | |
} | |
// Ignore an older term | |
if req.Term < r.getCurrentTerm() { | |
return | |
} | |
// Increase the term if we see a newer one | |
if req.Term > r.getCurrentTerm() { | |
// Ensure transition to follower | |
r.logger.Debug("lost leadership because received a requestVote with a newer term") | |
// 自己成为follow | |
r.setState(Follower) | |
// 成为current term | |
r.setCurrentTerm(req.Term) | |
resp.Term = req.Term | |
} | |
// Check if we have voted yet | |
// 是否有投票过 | |
lastVoteTerm, err := r.stable.GetUint64(keyLastVoteTerm) | |
if err != nil && err.Error() != "not found" { | |
r.logger.Error("failed to get last vote term", "error", err) | |
return | |
} | |
// 获取上次投票的结果 | |
lastVoteCandBytes, err := r.stable.Get(keyLastVoteCand) | |
if err != nil && err.Error() != "not found" { | |
r.logger.Error("failed to get last vote candidate", "error", err) | |
return | |
} | |
// Check if we've voted in this election before | |
// 有投票过, | |
if lastVoteTerm == req.Term && lastVoteCandBytes != nil { | |
r.logger.Info("duplicate requestVote for same term", "term", req.Term) | |
if bytes.Compare(lastVoteCandBytes, req.Candidate) == 0 { | |
r.logger.Warn("duplicate requestVote from", "candidate", candidate) | |
// 已经投票了 | |
resp.Granted = true | |
} | |
// 别的节点,那么直接false | |
return | |
} | |
// Reject if their term is older | |
lastIdx, lastTerm := r.getLastEntry() | |
// 本地的term大于上次的log term,那么直接vote false | |
if lastTerm > req.LastLogTerm { | |
r.logger.Warn("rejecting vote request since our last term is greater", | |
"candidate", candidate, | |
"last-term", lastTerm, | |
"last-candidate-term", req.LastLogTerm) | |
return | |
} | |
// term相同,并且相同的term,本地logindex 的大于请求lastLogIndex | |
if lastTerm == req.LastLogTerm && lastIdx > req.LastLogIndex { | |
r.logger.Warn("rejecting vote request since our last index is greater", | |
"candidate", candidate, | |
"last-index", lastIdx, | |
"last-candidate-index", req.LastLogIndex) | |
return | |
} | |
// Persist a vote for safety | |
// 持久化投票结果 | |
if err := r.persistVote(req.Term, req.Candidate); err != nil { | |
r.logger.Error("failed to persist vote", "error", err) | |
return | |
} | |
resp.Granted = true | |
r.setLastContact() | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment