From c1653a2ac480bac397a535b0783996511abacb7d Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 31 Oct 2026 04:11:45 +0100 Subject: compute per-peer totals in /admin/stats once --- src/api/dashboard/mod.rs | 6 ++++-- src/api/stats.rs | 28 +++++++++++++++------------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/api/dashboard/mod.rs b/src/api/dashboard/mod.rs index ad907ed..0a15570 100644 --- a/src/api/dashboard/mod.rs +++ b/src/api/dashboard/mod.rs @@ -257,8 +257,10 @@ impl Graph { /// The snapshot: the node, its figures, its peers, and the map. async fn build(state: &AppState, graph: &Graph) -> JsonValue { - let stats = serde_json::to_value(super::stats::collect(state).await).unwrap_or_default(); - let peers = serde_json::to_value(super::peers::peer_list(state).await).unwrap_or_default(); + // The peers once, for their list and the figures' totals over them. + let list = super::peers::peer_list(state).await; + let stats = serde_json::to_value(super::stats::collect(state, &list).await).unwrap_or_default(); + let peers = serde_json::to_value(&list).unwrap_or_default(); let aliases = { let replica = state.doc.read().await; members::aliases(&replica.doc) diff --git a/src/api/stats.rs b/src/api/stats.rs index b9314e2..9e1b278 100644 --- a/src/api/stats.rs +++ b/src/api/stats.rs @@ -13,7 +13,7 @@ use std::collections::BTreeMap; use serde::Serialize; -use super::peers::EpochInfo; +use super::peers::{EpochInfo, PeerListResponse, peer_list}; use crate::state::{AppState, Incidents}; use crate::swarm::{members, stability, topology}; use crate::transport::stats::TransportStats; @@ -237,12 +237,12 @@ pub(crate) async fn get_relay_only_stats( /// `GET /admin/stats`. pub(crate) async fn get_stats(State(state): State, headers: HeaderMap) -> Response { - let stats = collect(&state).await; + let list = peer_list(&state).await; + let stats = collect(&state, &list).await; let accept = headers .get(header::ACCEPT) .and_then(|value| value.to_str().ok()); if prometheus::wanted(accept) { - let list = super::peers::peer_list(&state).await; let body = prometheus::render(&stats, &list); ([(header::CONTENT_TYPE, prometheus::CONTENT_TYPE)], body).into_response() } else { @@ -250,8 +250,9 @@ pub(crate) async fn get_stats(State(state): State, headers: HeaderMap) } } -/// What `GET /admin/stats` answers as JSON, for others to show too (the dashboard). -pub(crate) async fn collect(state: &AppState) -> StatsResponse { +/// What `GET /admin/stats` answers as JSON, for others to show too (the dashboard); its +/// totals over the peers from their list (`peer_list`), read once for both. +pub(crate) async fn collect(state: &AppState, list: &PeerListResponse) -> StatsResponse { let node = state.stats.snapshot(); let (heads, tier, remakes) = { @@ -270,16 +271,17 @@ pub(crate) async fn collect(state: &AppState) -> StatsResponse { let (connected_fraction, observed) = stability::measured(state); let mut incidents = Incidents::default(); - let mut last_from_neighbour: Option = None; + let mut last_from_neighbour_secs: Option = None; let mut diverged_peers = 0; - for (peer, peer_state) in state.peers_snapshot().await { - let peer_state = peer_state.lock().await; - incidents.add(&peer_state.incidents); - if peer_state.diverged_since.is_some() { + for peer in list.peers.values() { + incidents.add(&peer.incidents); + if peer.diverged_for_secs.is_some() { diverged_peers += 1; } - if topology::is_neighbour(state, &peer) { - last_from_neighbour = last_from_neighbour.max(peer_state.last_sync_rx); + if peer.neighbour + && let Some(secs) = peer.last_sync_secs_ago + { + last_from_neighbour_secs = Some(last_from_neighbour_secs.map_or(secs, |s| s.min(secs))); } } @@ -315,7 +317,7 @@ pub(crate) async fn collect(state: &AppState) -> StatsResponse { archived_epochs: remakes.archived_epochs, }, sync: SyncStats { - last_from_neighbour_secs: last_from_neighbour.map(|at| at.elapsed().as_secs()), + last_from_neighbour_secs, diverged_peers, largest_received_bytes: node.largest_sync_received, }, -- cgit v1.3.1