summaryrefslogtreecommitdiffstats
path: root/src/swarm/topology.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-24 06:09:22 +0200
committertv <tv@krebsco.de>2026-10-24 06:09:22 +0200
commit490234bbd44356da1cca0ad62b044e0cba70a226 (patch)
tree74c1b840a125bc9317602c63e29cbf8f81853b3d /src/swarm/topology.rs
parente0ab17f665bb476329e0c7f980f31bb10cbfc944 (diff)
add swarm stats
Diffstat (limited to 'src/swarm/topology.rs')
-rw-r--r--src/swarm/topology.rs38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/swarm/topology.rs b/src/swarm/topology.rs
index 8e25a2a..c5a02f1 100644
--- a/src/swarm/topology.rs
+++ b/src/swarm/topology.rs
@@ -48,6 +48,44 @@ pub(crate) fn is_full_mesh(state: &AppState) -> bool {
.is_none_or(|view| view.full_mesh)
}
+/// The current view in numbers, once known.
+#[derive(Debug, Clone, Copy)]
+pub(crate) struct Summary {
+ /// Registered members, us included.
+ pub(crate) members: usize,
+ /// Members other than us not currently judged unreachable.
+ pub(crate) reachable: usize,
+ pub(crate) stable: usize,
+ pub(crate) neighbours: usize,
+ pub(crate) stable_neighbours: usize,
+ pub(crate) full_mesh: bool,
+}
+
+pub(crate) fn summary(state: &AppState) -> Option<Summary> {
+ let local = state.local_id();
+ state
+ .neighbours
+ .read()
+ .unwrap_or_else(|poisoned| poisoned.into_inner())
+ .as_ref()
+ .map(|view| Summary {
+ members: view.members.len(),
+ reachable: view
+ .members
+ .iter()
+ .filter(|m| m.as_str() != local && !view.unreachable.contains(*m))
+ .count(),
+ stable: view.stable.len(),
+ neighbours: view.neighbours.len(),
+ stable_neighbours: view
+ .neighbours
+ .iter()
+ .filter(|m| view.stable.contains(*m))
+ .count(),
+ full_mesh: view.full_mesh,
+ })
+}
+
/// Whether we initiate contact with `peer`: HELLOs, keepalives, dormancy checks, sync
/// openings. Everyone is a neighbour until the view is known (while joining, or before
/// any member registered), so joining works as in a full mesh. We always *answer*