diff options
| author | tv <tv@krebsco.de> | 2026-10-24 04:20:21 +0200 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-24 04:21:11 +0200 |
| commit | c2468964b11bd3606f03375c370fd181a1723113 (patch) | |
| tree | 96c9c4a126efc928716491b4c110a4da7de6ead7 /src/state.rs | |
| parent | 5710d1a367a1914d09e0eefe6984408c95a7dd2e (diff) | |
find reachable neighbours
Diffstat (limited to 'src/state.rs')
| -rw-r--r-- | src/state.rs | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/state.rs b/src/state.rs index 64fe6a4..7574e35 100644 --- a/src/state.rs +++ b/src/state.rs @@ -137,8 +137,18 @@ pub(crate) struct PeerState { /// How many heads its most recent keepalive listed (None if it sent a digest). pub(crate) reported_heads: Option<usize>, + + /// 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 + /// dormant). Cleared by any message from it; ignored after `dormant_probe`, so the + /// peer becomes a neighbour candidate again and gets tried once more. + pub(crate) unreachable_since: Option<Instant>, } +/// Unanswered HELLOs after which a peer counts as unreachable (1 + 2 + 4 s apart). +const UNREACHABLE_AFTER_HELLOS: u32 = 3; + /// One Automerge sync with a peer, from a reset to the next. Everything a reset must /// forget lives here, so a reset replaces it whole and can't miss a field. #[derive(Clone)] @@ -284,6 +294,8 @@ impl PeerState { reports_ready: None, syncs_with_us: None, reported_heads: None, + hello_attempts: 0, + unreachable_since: None, } } @@ -309,6 +321,8 @@ impl PeerState { /// Records inbound activity. Returns true if the peer was dormant. pub(crate) fn mark_seen(&mut self, now: Instant) -> bool { self.last_seen = Some(now); + self.hello_attempts = 0; + self.unreachable_since = None; if matches!(self.liveness, Liveness::Dormant { .. }) { self.liveness = Liveness::Active; @@ -321,6 +335,21 @@ impl PeerState { false } + /// A HELLO went out (or failed to). After the third unanswered one, the peer counts + /// as unreachable. + pub(crate) fn hello_sent(&mut self, now: Instant) { + self.hello_attempts += 1; + if self.hello_attempts >= UNREACHABLE_AFTER_HELLOS { + self.unreachable_since.get_or_insert(now); + } + } + + /// Whether to leave the peer out when choosing neighbours (`swarm::topology`). + pub(crate) fn is_unreachable(&self, timing: &Timing, now: Instant) -> bool { + self.unreachable_since + .is_some_and(|since| now.saturating_duration_since(since) < timing.dormant_probe) + } + /// No more HELLO retries (the peer isn't our neighbour any more). A HELLO in flight /// finishes; a later handshake starts over. pub(crate) fn stop_hello_retries(&mut self) { @@ -336,6 +365,7 @@ impl PeerState { } self.liveness = Liveness::Dormant { since: now }; + self.unreachable_since.get_or_insert(now); self.reset_sync(); if self.hello_state != HelloState::Sending { |
