1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
///|
/// Whether a candidate's log, described by its last entry's term and index,
/// is at least as up-to-date as this node's log (Raft §5.4.1). A log with a
/// higher last term wins; on a tie the longer log wins.
fn Node::candidate_log_up_to_date(
self : Node,
last_log_term : UInt64,
last_log_index : UInt64,
) -> Bool {
let my_term = self.last_log_term()
last_log_term > my_term ||
(last_log_term == my_term && last_log_index >= self.last_log_index())
}
///|
/// Handle a RequestVote RPC (Raft §5.2, §5.4.1). A larger term makes this
/// node step down first. The vote is granted only when this node has not yet
/// voted for a different candidate in the term and the candidate's log is at
/// least as up-to-date as its own.
pub fn Node::handle_request_vote(
self : Node,
args : RequestVoteArgs,
) -> RequestVoteReply {
if args.term < self.current_term {
return { term: self.current_term, vote_granted: false }
}
if args.term > self.current_term {
self.become_follower(args.term)
}
let can_vote = match self.voted_for {
None => true
Some(id) => id == args.candidate_id
}
let granted = can_vote &&
self.candidate_log_up_to_date(args.last_log_term, args.last_log_index)
if granted {
self.voted_for = Some(args.candidate_id)
}
{ term: self.current_term, vote_granted: granted }
}