node: extract immutable state into a shared context and atomic metric registry

Store node counters in an atomic metric registry read through &self, and
introduce a shared NodeContext bundle holding the effectively-immutable
fields (config, identity, startup epoch, node profile, capability limits).
Source the immutable config and identity reads across the receive hot
path, the XX handshake/session/rekey state machines, and the discovery,
tree, bloom, retry, and lifecycle modules through the context accessors.
Includes the bloom delta/full/NACK/resize and byte-total counters in the
registry. The Node fields and the context are rebuilt in lockstep at every
mutation site.
This commit is contained in:
Johnathan Corgan
2026-06-02 13:05:03 +00:00
parent 88e48fdc68
commit e181df0ac4
30 changed files with 1301 additions and 1003 deletions
+86
View File
@@ -0,0 +1,86 @@
//! Shared immutable context bundle.
//!
//! [`NodeContext`] groups the [`Node`](super::Node)'s effectively-immutable
//! fields behind a single `Arc` so that handlers can eventually borrow a
//! cheap `&NodeContext` clone instead of `&self`.
//!
//! During the migration it is a *parallel, authoritative* copy of the
//! corresponding `Node` fields: both are kept in lockstep at the only three
//! mutation points — the constructor, [`update_peers`](super::Node::update_peers),
//! and the test-only `set_max_*` setters — via
//! [`Node::rebuild_context`](super::Node::rebuild_context). Readers migrate
//! onto the bundle incrementally; the duplicated `Node` fields are removed
//! once the last reader has moved over.
use std::sync::Arc;
use crate::protocol::NodeProfile;
use crate::{Config, Identity};
/// Effectively-immutable `Node` state, shared via `Arc<NodeContext>`.
#[derive(Clone)]
pub(crate) struct NodeContext {
/// Loaded configuration. A static snapshot: replaced wholesale (never
/// interior-mutated) when `update_peers` rebuilds the runtime peer list.
pub config: Arc<Config>,
/// This node's cryptographic identity.
pub identity: Identity,
/// Random epoch generated at startup for peer restart detection.
// Consumed by readers migrating in a later sub-PR.
#[allow(dead_code)]
pub startup_epoch: [u8; 8],
/// Instant when the node was created, for uptime reporting.
pub started_at: std::time::Instant,
/// Whether this is a leaf-only node.
pub is_leaf_only: bool,
/// This node's routing profile (Full, NonRouting, Leaf).
pub node_profile: NodeProfile,
/// Maximum connections (0 = unlimited).
// Consumed by readers migrating in a later sub-PR.
#[allow(dead_code)]
pub max_connections: usize,
/// Maximum peers (0 = unlimited).
// Consumed by readers migrating in a later sub-PR.
#[allow(dead_code)]
pub max_peers: usize,
/// Maximum links (0 = unlimited).
// Consumed by readers migrating in a later sub-PR.
#[allow(dead_code)]
pub max_links: usize,
}
impl NodeContext {
/// Build a context bundle from the individual values.
#[allow(clippy::too_many_arguments)]
pub fn new(
config: Arc<Config>,
identity: Identity,
startup_epoch: [u8; 8],
started_at: std::time::Instant,
is_leaf_only: bool,
node_profile: NodeProfile,
max_connections: usize,
max_peers: usize,
max_links: usize,
) -> Self {
Self {
config,
identity,
startup_epoch,
started_at,
is_leaf_only,
node_profile,
max_connections,
max_peers,
max_links,
}
}
}