(&mut self)
| 94 | } |
| 95 | |
| 96 | pub(super) fn become_leader(&mut self) { |
| 97 | self.role = NodeRole::Leader; |
| 98 | self.leader_id = self.config.node_id; |
| 99 | |
| 100 | // Leader tracks voter peers, learner peers, and observer peers for |
| 101 | // replication. Only voters count toward the commit quorum (see |
| 102 | // `try_advance_commit_index`). Learners still receive entries so they |
| 103 | // can catch up for promotion. Observers receive entries and ack |
| 104 | // advisorily but are never counted in quorum. |
| 105 | let mut ls = LeaderState::new( |
| 106 | &self.config.peers, |
| 107 | &self.config.observers, |
| 108 | self.log.last_index(), |
| 109 | ); |
| 110 | for &learner in &self.config.learners { |
| 111 | ls.add_peer(learner, self.log.last_index()); |
| 112 | } |
| 113 | self.leader_state = Some(ls); |
| 114 | |
| 115 | info!( |
| 116 | node = self.config.node_id, |
| 117 | group = self.config.group_id, |
| 118 | term = self.hard_state.current_term, |
| 119 | voters = self.config.peers.len(), |
| 120 | learners = self.config.learners.len(), |
| 121 | "became leader" |
| 122 | ); |
| 123 | |
| 124 | // Raft paper §5.4.2: leader appends a no-op entry. |
| 125 | let noop = LogEntry { |
| 126 | term: self.hard_state.current_term, |
| 127 | index: self.log.last_index() + 1, |
| 128 | data: Vec::new(), |
| 129 | }; |
| 130 | let _ = self.log.append(noop); |
| 131 | |
| 132 | // Single-voter cluster: commit the no-op immediately. |
| 133 | if self.config.cluster_size() == 1 { |
| 134 | self.volatile.commit_index = self.log.last_index(); |
| 135 | self.collect_committed_entries(); |
| 136 | } |
| 137 | |
| 138 | self.replicate_to_all(); |
| 139 | } |
| 140 | |
| 141 | /// Send `AppendEntries` to every tracked peer (voters + learners + observers). |
| 142 | /// |
no test coverage detected