diff options
| author | tv <tv@krebsco.de> | 2026-11-04 22:15:18 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-04 22:15:18 +0100 |
| commit | a1585a3db53ee59fe941622d698638322b585267 (patch) | |
| tree | 097f53b4cb6efe4e0da54d01f960a707cc0b7922 /src/api | |
| parent | e1e6c8b8faead6c348f1b775baa50a30867c0016 (diff) | |
hop delays
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/peers.rs | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/api/peers.rs b/src/api/peers.rs index 6662a55..b00593f 100644 --- a/src/api/peers.rs +++ b/src/api/peers.rs @@ -74,6 +74,34 @@ pub(crate) struct PeerStatus { /// How far its clock is ahead of ours, give or take (`Transport::clock_offset`); /// absent before a PONG from it. pub(crate) clock: Option<ClockOffset>, + /// How long its sync messages take to come (`swarm::hop`); absent before one came + /// while we knew its clock. + pub(crate) hop_delay: Option<HopDelayInfo>, +} + +/// How long a peer's sync messages take to come, by its clock and ours, its offset +/// taken off: good to half the round trip (the offset's error), the same for every +/// message while the offset stands, so the minutes' means show a trend exactly. +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct HopDelayInfo { + /// Messages measured since we started. + pub(crate) count: u64, + pub(crate) mean_ms: u64, + /// The bucket bounds by which half, and 99%, came (`/admin/stats`' propagation + /// buckets); absent if beyond the last. + pub(crate) half_within_ms: Option<u64>, + pub(crate) p99_within_ms: Option<u64>, + /// Messages that took less than nothing by the clocks: the offset's error was larger + /// (counted as 0 above). + pub(crate) below_zero: u64, + /// The mean of each of the last 15 minutes, oldest first (the last is the current + /// one); null for a minute without messages. May be negative, as `belowZero`. + pub(crate) by_minute_ms: Vec<Option<i64>>, + /// Half the round trip to it now, from PINGs (which wait behind nothing): what a + /// message would take with nothing waiting anywhere; what the delay takes beyond it + /// waits in queues (and is the offset's error). Absent without a recent round trip. + pub(crate) half_rtt_ms: Option<u64>, } #[derive(Debug, Serialize)] @@ -163,6 +191,19 @@ pub(crate) async fn peer_list(state: &AppState) -> PeerListResponse { let addresses = state.transport.addresses_of(&peer); let destination = state.transport.destination(&peer); let clock = state.transport.clock_offset(&peer); + let hops = &ps.hop_delays; + let hop_delay = (hops.all.count > 0).then(|| HopDelayInfo { + count: hops.all.count, + mean_ms: hops.all.sum_ms / hops.all.count, + half_within_ms: hops.all.within(0.5), + p99_within_ms: hops.all.within(0.99), + below_zero: hops.all.ahead, + by_minute_ms: hops.by_minute(now), + half_rtt_ms: state + .lock_rtt() + .effective(&peer, now, state.timing.rtt_fresh_for()) + .map(|rtt| rtt.as_millis() as u64 / 2), + }); peers.insert( peer, PeerStatus { @@ -192,6 +233,7 @@ pub(crate) async fn peer_list(state: &AppState) -> PeerListResponse { incidents: ps.incidents, sync_throughput, clock, + hop_delay, }, ); } |
