nodedb_raft/node/rpc/
request_vote.rs1use tracing::debug;
6
7use crate::message::{RequestVoteRequest, RequestVoteResponse};
8use crate::node::core::RaftNode;
9use crate::state::NodeRole;
10use crate::storage::LogStorage;
11
12impl<S: LogStorage> RaftNode<S> {
13 pub fn handle_request_vote(&mut self, req: &RequestVoteRequest) -> RequestVoteResponse {
19 match self.role {
20 NodeRole::Learner | NodeRole::Observer => {
21 return RequestVoteResponse {
23 term: self.hard_state.current_term,
24 vote_granted: false,
25 };
26 }
27 NodeRole::Follower | NodeRole::Candidate | NodeRole::Leader => {}
28 }
29
30 if req.term > self.hard_state.current_term {
31 self.become_follower(req.term);
32 }
33
34 if req.term < self.hard_state.current_term {
35 return RequestVoteResponse {
36 term: self.hard_state.current_term,
37 vote_granted: false,
38 };
39 }
40
41 let voted_for = self.hard_state.voted_for;
42 let can_vote = voted_for == 0 || voted_for == req.candidate_id;
43
44 let log_ok = req.last_log_term > self.log.last_term()
45 || (req.last_log_term == self.log.last_term()
46 && req.last_log_index >= self.log.last_index());
47
48 if can_vote && log_ok {
49 self.hard_state.voted_for = req.candidate_id;
50 self.persist_hard_state();
51 self.reset_election_timeout();
52
53 debug!(
54 node = self.config.node_id,
55 group = self.config.group_id,
56 candidate = req.candidate_id,
57 term = req.term,
58 "granted vote"
59 );
60
61 RequestVoteResponse {
62 term: self.hard_state.current_term,
63 vote_granted: true,
64 }
65 } else {
66 RequestVoteResponse {
67 term: self.hard_state.current_term,
68 vote_granted: false,
69 }
70 }
71 }
72
73 pub fn handle_request_vote_response(&mut self, peer: u64, resp: &RequestVoteResponse) {
75 if resp.term > self.hard_state.current_term {
76 self.become_follower(resp.term);
77 return;
78 }
79
80 if self.role != NodeRole::Candidate {
81 return;
82 }
83
84 if resp.vote_granted {
85 self.votes_received.insert(peer);
86 let vote_count = self.votes_received.len() + 1; if vote_count >= self.config.quorum() {
89 self.become_leader();
90 }
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use std::time::{Duration, Instant};
98
99 use crate::message::RequestVoteRequest;
100 use crate::node::core::RaftNode;
101 use crate::node::rpc::test_helpers::{observer_self_config, test_config};
102 use crate::state::NodeRole;
103 use crate::storage::MemStorage;
104
105 #[test]
106 fn vote_grant_and_reject() {
107 let config = test_config(1, vec![2, 3]);
108 let mut node = RaftNode::new(config, MemStorage::new());
109
110 let req = RequestVoteRequest {
111 term: 1,
112 candidate_id: 2,
113 last_log_index: 0,
114 last_log_term: 0,
115 group_id: 1,
116 };
117 let resp = node.handle_request_vote(&req);
118 assert!(resp.vote_granted);
119
120 let req2 = RequestVoteRequest {
121 term: 1,
122 candidate_id: 3,
123 last_log_index: 0,
124 last_log_term: 0,
125 group_id: 1,
126 };
127 let resp2 = node.handle_request_vote(&req2);
128 assert!(!resp2.vote_granted);
129 }
130
131 #[test]
132 fn learner_rejects_vote_request() {
133 let mut config = test_config(2, vec![1]);
134 config.starts_as_learner = true;
135 let mut node = RaftNode::new(config, MemStorage::new());
136 assert_eq!(node.role(), NodeRole::Learner);
137
138 let req = RequestVoteRequest {
139 term: 5,
140 candidate_id: 1,
141 last_log_index: 10,
142 last_log_term: 4,
143 group_id: 1,
144 };
145 let resp = node.handle_request_vote(&req);
146 assert!(
147 !resp.vote_granted,
148 "learner must never grant a vote, got {resp:?}"
149 );
150 }
151
152 #[test]
153 fn three_node_election() {
154 let config1 = test_config(1, vec![2, 3]);
155 let config2 = test_config(2, vec![1, 3]);
156 let config3 = test_config(3, vec![1, 2]);
157
158 let mut node1 = RaftNode::new(config1, MemStorage::new());
159 let mut node2 = RaftNode::new(config2, MemStorage::new());
160 let mut node3 = RaftNode::new(config3, MemStorage::new());
161
162 node1.election_deadline = Instant::now() - Duration::from_millis(1);
163 node1.tick();
164 assert_eq!(node1.role(), NodeRole::Candidate);
165
166 let ready = node1.take_ready();
167 assert_eq!(ready.vote_requests.len(), 2);
168
169 let resp2 = node2.handle_request_vote(&ready.vote_requests[0].1);
170 let resp3 = node3.handle_request_vote(&ready.vote_requests[1].1);
171 assert!(resp2.vote_granted);
172 assert!(resp3.vote_granted);
173
174 node1.handle_request_vote_response(2, &resp2);
175 assert_eq!(node1.role(), NodeRole::Leader);
176 }
177
178 #[test]
180 fn observer_self_never_grants_vote() {
181 let mut obs = RaftNode::new(observer_self_config(5), MemStorage::new());
182 assert_eq!(obs.role(), NodeRole::Observer);
183
184 let req = RequestVoteRequest {
185 term: 10,
186 candidate_id: 1,
187 last_log_index: 100,
188 last_log_term: 9,
189 group_id: 1,
190 };
191 let resp = obs.handle_request_vote(&req);
192 assert!(!resp.vote_granted, "observer must never grant a vote");
193 assert_eq!(obs.role(), NodeRole::Observer, "role must stay Observer");
194 }
195
196 #[test]
198 fn observer_tick_does_not_start_election() {
199 let mut obs = RaftNode::new(observer_self_config(5), MemStorage::new());
200 obs.election_deadline = Instant::now() - Duration::from_millis(1);
201 obs.tick();
202 assert_eq!(obs.role(), NodeRole::Observer);
203 assert_eq!(obs.current_term(), 0);
204 }
205}