aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/peers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/peers.rs')
-rw-r--r--src/api/peers.rs42
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,
},
);
}