MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / should_bootstrap

Function should_bootstrap

nodedb-cluster/src/bootstrap/probe.rs:84–173  ·  view source on GitHub ↗

Decide whether this node should bootstrap a new cluster. Returns `true` iff any of the following hold: 1. `config.force_bootstrap` is set (operator escape hatch). 2. This node's `listen_addr` is the lexicographically smallest entry in `config.seed_nodes` — the deterministic elected bootstrapper. Returns `false` in every other case, including when the designated bootstrapper is currently unreach

(config: &ClusterConfig, transport: &NexarTransport)

Source from the content-addressed store, hash-verified

82/// and logging, not a decision input. With a deterministic rule there
83/// is nothing to race on.
84pub(super) async fn should_bootstrap(config: &ClusterConfig, transport: &NexarTransport) -> bool {
85 if config.force_bootstrap {
86 info!(
87 node_id = config.node_id,
88 listen_addr = %config.listen_addr,
89 "force_bootstrap flag set — bootstrapping unconditionally"
90 );
91 return true;
92 }
93
94 let designated = match designated_bootstrapper(&config.seed_nodes) {
95 Some(addr) => addr,
96 None => {
97 // Empty seed list — caller already treats this as an
98 // implicit single-node bootstrap (`seed_nodes = [self]`
99 // fallback in `TestNode::spawn` / the main binary's
100 // config layer). Bootstrap is the only reasonable choice.
101 return true;
102 }
103 };
104
105 if designated == config.listen_addr {
106 info!(
107 node_id = config.node_id,
108 listen_addr = %config.listen_addr,
109 "this node is the designated bootstrapper"
110 );
111 return true;
112 }
113
114 info!(
115 node_id = config.node_id,
116 listen_addr = %config.listen_addr,
117 %designated,
118 "deferring to designated bootstrapper; probing for liveness"
119 );
120
121 // Non-blocking best-effort probe — each attempt is bounded by
122 // PROBE_TIMEOUT, so the total window is at most
123 // MAX_PROBE_ATTEMPTS * (PROBE_TIMEOUT + PROBE_INTERVAL). Exits
124 // early as soon as the bootstrapper answers, so the common case is
125 // a single sub-second round trip.
126 for attempt in 0..MAX_PROBE_ATTEMPTS {
127 let probe_result = tokio::time::timeout(
128 PROBE_TIMEOUT,
129 ping_probe(designated, transport, config.node_id),
130 )
131 .await;
132
133 match probe_result {
134 Ok(Ok(())) => {
135 info!(
136 node_id = config.node_id,
137 %designated,
138 attempt,
139 "designated bootstrapper is up"
140 );
141 return false;

Calls 2

designated_bootstrapperFunction · 0.85
ping_probeFunction · 0.85

Tested by

no test coverage detected