From 7997793798b8364212fd0f009a68394d61a83e47 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 31 Oct 2026 06:19:34 +0100 Subject: dashboard: try to get links dormant immediately --- src/state/peer.rs | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/state/peer.rs') diff --git a/src/state/peer.rs b/src/state/peer.rs index 99f912b..f6e8786 100644 --- a/src/state/peer.rs +++ b/src/state/peer.rs @@ -137,6 +137,10 @@ pub(crate) struct PeerState { /// How many heads its most recent keepalive listed (None if it sent a digest). pub(crate) reported_heads: Option, + /// It said farewell (`say_farewell`): what else that run of it still sends while it + /// stops doesn't make it active again; a message from another run does (`returned`). + pub(crate) left: bool, + /// HELLOs sent in the current handshake attempt without hearing anything back. pub(crate) hello_attempts: u32, /// Since when we consider the peer unreachable (three unanswered HELLOs, or @@ -212,6 +216,7 @@ impl PeerState { reports_ready: None, syncs_with_us: None, reported_heads: None, + left: false, hello_attempts: 0, unreachable_since: None, incidents: Incidents::default(), @@ -244,9 +249,13 @@ impl PeerState { now.saturating_duration_since(self.last_seen.unwrap_or(self.added_at)) } - /// Records inbound activity. Returns true if the peer was dormant. + /// Records inbound activity. Returns true if the peer was dormant. From a peer that + /// said farewell (`left`), only that it was heard from. pub(crate) fn mark_seen(&mut self, now: Instant) -> bool { self.last_seen = Some(now); + if self.left { + return false; + } self.hello_attempts = 0; self.unreachable_since = None; self.probe_backoff.reset(); @@ -333,6 +342,7 @@ impl PeerState { /// The peer said farewell (it is shutting down): Dormant now, without waiting for /// its silence, and not counted as an incident. Returns true on the transition. pub(crate) fn say_farewell(&mut self, now: Instant) -> bool { + self.left = true; if self.liveness.is_dormant() { return false; } @@ -340,6 +350,14 @@ impl PeerState { true } + /// A message from `run` of the peer (a HELLO's or HELLO_REPLY's): a run other than + /// the one that said farewell is back (`left`). + pub(crate) fn returned(&mut self, run: crate::transport::RunId) { + if self.run_id != Some(run) { + self.left = false; + } + } + fn go_dormant(&mut self, now: Instant) { self.liveness = Liveness::Dormant { since: now }; self.unreachable_since.get_or_insert(now); @@ -488,6 +506,25 @@ mod tests { assert!(silent.liveness.is_dormant()); } + /// After its farewell, a peer stays dormant whatever its stopping run still sends; + /// its next run makes it active again. + #[test] + fn dormant_after_farewell_until_back() { + let timing = Timing::from_keepalive(Duration::from_secs(60), Duration::from_secs(300)); + let mut peer = PeerState::new(true, &timing); + let now = peer.added_at; + peer.run_id = Some([1; 16]); + peer.mark_seen(now); + assert!(peer.say_farewell(now)); + assert!(!peer.mark_seen(now), "a straggler from the same run"); + assert!(peer.liveness.is_dormant() && peer.is_unreachable()); + peer.returned([1; 16]); + assert!(!peer.mark_seen(now), "the same run again"); + peer.returned([2; 16]); + assert!(peer.mark_seen(now), "its next run"); + assert!(!peer.liveness.is_dormant() && !peer.is_unreachable()); + } + /// The two sides of a pair take turns: each sends every other interval. #[test] fn keepalives_take_turns() { -- cgit v1.3.1