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

Function handle_join_request

nodedb-cluster/src/bootstrap/handle_join.rs:39–115  ·  view source on GitHub ↗

Build a `JoinResponse` for an incoming `JoinRequest`. See module docs for semantics. Mutates `topology` only when the node is newly admitted; idempotent for re-joins with the same address. `cluster_id` is the id of the cluster this node belongs to — the join flow reads it from the local catalog and threads it through so the joining node can persist it and take the `restart()` path on a subsequen

(
    req: &JoinRequest,
    topology: &mut ClusterTopology,
    routing: &RoutingTable,
    cluster_id: u64,
)

Source from the content-addressed store, hash-verified

37/// catalog has not yet been populated; rejection responses also carry
38/// zero.
39pub fn handle_join_request(
40 req: &JoinRequest,
41 topology: &mut ClusterTopology,
42 routing: &RoutingTable,
43 cluster_id: u64,
44) -> JoinResponse {
45 // Validate the wire version carried in the JOIN payload (belt-and-suspenders
46 // check; the transport-level handshake already negotiated a compatible version
47 // before this RPC was dispatched). The `wire_version` field here is the
48 // cluster-wide schema version (`CLUSTER_WIRE_FORMAT_VERSION`), distinct from
49 // the transport-level RPC frame version. We require an exact match because
50 // this build uses floor == ceiling (no backward-compat window in the schema).
51 if req.wire_version != CLUSTER_WIRE_FORMAT_VERSION {
52 warn!(
53 node_id = req.node_id,
54 joiner_wire_version = req.wire_version,
55 expected_wire_version = CLUSTER_WIRE_FORMAT_VERSION,
56 "join request rejected: joiner cluster wire_version mismatch"
57 );
58 return reject(format!(
59 "joiner wire_version {} does not match this cluster's wire_version {} — \
60 rolling upgrade is required before this node can join",
61 req.wire_version, CLUSTER_WIRE_FORMAT_VERSION
62 ));
63 }
64
65 // Validate the listen address early.
66 let addr: SocketAddr = match req.listen_addr.parse() {
67 Ok(a) => a,
68 Err(e) => {
69 return reject(format!("invalid listen_addr '{}': {e}", req.listen_addr));
70 }
71 };
72
73 // Collision / idempotency check — both require reading the existing entry.
74 if let Some(existing) = topology.get_node(req.node_id) {
75 let existing_addr = existing.addr.clone();
76 if existing_addr != req.listen_addr {
77 // Same id, different address — reject.
78 return reject(format!(
79 "node_id {} already registered with different address {} (request: {})",
80 req.node_id, existing_addr, req.listen_addr
81 ));
82 }
83 // Same id, same address. If already Active we short-circuit —
84 // no topology mutation at all, just rebuild the wire response. If the
85 // node was in a non-Active state (Joining/Draining), normalize to
86 // Active now because it's clearly back online.
87 if existing.state != NodeState::Active
88 && let Some(entry) = topology.get_node_mut(req.node_id)
89 {
90 entry.state = NodeState::Active;
91 }
92 return build_response(topology, routing, cluster_id);
93 }
94
95 // Brand new node — admit as Active. Stamp the joiner's own
96 // wire version and identity fields onto its NodeInfo so every

Calls 11

get_nodeMethod · 0.80
get_node_mutMethod · 0.80
with_spki_pinMethod · 0.80
with_spiffe_idMethod · 0.80
with_wire_versionMethod · 0.80
rejectFunction · 0.70
build_responseFunction · 0.70
parseMethod · 0.45
cloneMethod · 0.45
lenMethod · 0.45
add_nodeMethod · 0.45