Restart from persisted state — load topology and routing from catalog.
(
config: &ClusterConfig,
catalog: &ClusterCatalog,
transport: &NexarTransport,
)
| 15 | |
| 16 | /// Restart from persisted state — load topology and routing from catalog. |
| 17 | pub(super) fn restart( |
| 18 | config: &ClusterConfig, |
| 19 | catalog: &ClusterCatalog, |
| 20 | transport: &NexarTransport, |
| 21 | ) -> Result<ClusterState> { |
| 22 | let topology = catalog |
| 23 | .load_topology()? |
| 24 | .ok_or_else(|| ClusterError::Transport { |
| 25 | detail: "catalog is bootstrapped but topology is missing".into(), |
| 26 | })?; |
| 27 | |
| 28 | let routing = catalog |
| 29 | .load_routing()? |
| 30 | .ok_or_else(|| ClusterError::Transport { |
| 31 | detail: "catalog is bootstrapped but routing table is missing".into(), |
| 32 | })?; |
| 33 | |
| 34 | // Reconstruct MultiRaft from routing table. A restarting node |
| 35 | // may be a voter (`info.members`) OR a learner (`info.learners`) |
| 36 | // — the latter is the window between an `AddLearner` commit |
| 37 | // and the follow-up `PromoteLearner` commit during a join. A |
| 38 | // node that crashes inside that window must still come back |
| 39 | // as a learner on restart; dropping the group entirely would |
| 40 | // leave the node permanently without any copy of it and |
| 41 | // silently broken. |
| 42 | let mut multi_raft = MultiRaft::new(config.node_id, routing.clone(), config.data_dir.clone()) |
| 43 | .with_election_timeout(config.election_timeout_min, config.election_timeout_max); |
| 44 | for (group_id, info) in routing.group_members() { |
| 45 | let is_voter = info.members.contains(&config.node_id); |
| 46 | let is_learner = info.learners.contains(&config.node_id); |
| 47 | |
| 48 | if is_voter { |
| 49 | let peers: Vec<u64> = info |
| 50 | .members |
| 51 | .iter() |
| 52 | .copied() |
| 53 | .filter(|&id| id != config.node_id) |
| 54 | .collect(); |
| 55 | multi_raft.add_group(*group_id, peers)?; |
| 56 | } else if is_learner { |
| 57 | // Voters are the full member set (none of them is |
| 58 | // self). Other learners catching up alongside us are |
| 59 | // tracked for replication too. |
| 60 | let voters = info.members.clone(); |
| 61 | let other_learners: Vec<u64> = info |
| 62 | .learners |
| 63 | .iter() |
| 64 | .copied() |
| 65 | .filter(|&id| id != config.node_id) |
| 66 | .collect(); |
| 67 | multi_raft.add_group_as_learner(*group_id, voters, other_learners)?; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // Register all known peers in the transport. |
| 72 | for node in topology.all_nodes() { |
| 73 | if node.node_id != config.node_id |
| 74 | && let Some(addr) = node.socket_addr() |
no test coverage detected