diff options
| author | tv <tv@krebsco.de> | 2026-10-26 05:50:14 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-26 05:50:14 +0100 |
| commit | f00378e8609e0117132d7aab3f4468a1721f52fa (patch) | |
| tree | 5a252c09685cf833f5e1a7fc2e2e4e4b3f3c02dd /src | |
| parent | 51e8c8e38c05d98487784e21f9df54cc18875b8b (diff) | |
keep silent strangers for a day
Diffstat (limited to 'src')
| -rw-r--r-- | src/swarm/peer/forget.rs | 40 | ||||
| -rw-r--r-- | src/swarm/peer/worker.rs | 3 |
2 files changed, 40 insertions, 3 deletions
diff --git a/src/swarm/peer/forget.rs b/src/swarm/peer/forget.rs index 624ca97..df09c3c 100644 --- a/src/swarm/peer/forget.rs +++ b/src/swarm/peer/forget.rs @@ -1,5 +1,8 @@ //! Swarm-wide forget records (`_continuum/forgotten/<pk>`): a peer forgotten on one -//! node is forgotten by all; a forgotten node that is alive cancels its record. +//! node is forgotten by all; a forgotten node that is alive cancels its record. And +//! locally, strangers that went silent. + +use std::time::Duration; use automerge::AutoCommit; use tokio::time::Instant; @@ -7,7 +10,7 @@ use tracing::{info, warn}; use crate::document::meta; use crate::document::store::{self, StoreError}; -use crate::state::AppState; +use crate::state::{AppState, Standing}; fn forgotten_dir() -> Vec<String> { meta::path(&[meta::FORGOTTEN]) @@ -77,3 +80,36 @@ pub(super) async fn apply_forget_records(state: &AppState) { }) .await; } + +/// How long a peer that never became a member is kept once nothing more is heard from +/// it: one listed to us that never answered, or one that keeps failing the handshake +/// (another swarm, a wrong key). Anyone can name peers to a node, so without a limit +/// the map of peers would only grow. +const STRANGER_KEPT: Duration = Duration::from_secs(24 * 3600); + +/// Forgets peers that never became members and were silent for `STRANGER_KEPT`. Only +/// here, not swarm-wide; one that comes back is a stranger again. +pub(super) async fn forget_strangers(state: &AppState) { + let now = Instant::now(); + let mut strangers = Vec::new(); + for (peer, peer_state) in state.peers_snapshot().await { + let peer_state = peer_state.lock().await; + let quiet_since = peer_state.last_seen.unwrap_or(peer_state.added_at); + if !matches!(peer_state.standing, Standing::Member { .. }) + && now.saturating_duration_since(quiet_since) >= STRANGER_KEPT + { + strangers.push(peer); + } + } + if strangers.is_empty() { + return; + } + let mut peer_states = state.peer_states.write().await; + for peer in &strangers { + peer_states.remove(peer); + } + info!( + forgotten = strangers.len(), + "Forgot peers that never became members and were silent for a day" + ); +} diff --git a/src/swarm/peer/worker.rs b/src/swarm/peer/worker.rs index a27f144..5161ae6 100644 --- a/src/swarm/peer/worker.rs +++ b/src/swarm/peer/worker.rs @@ -8,7 +8,7 @@ use std::time::Duration; use tokio::time::{Instant, MissedTickBehavior}; use tracing::{debug, info, warn}; -use super::forget::apply_forget_records; +use super::forget::{apply_forget_records, forget_strangers}; use super::handshake::retry_hello_if_due; use super::keepalive::send_ping; use crate::locks::MutexExt; @@ -94,6 +94,7 @@ pub(crate) async fn run_peer_worker(state: AppState) { if last_forget_check.is_none_or(|t| t.elapsed() >= FORGET_CHECK_INTERVAL) { apply_forget_records(&state).await; + forget_strangers(&state).await; crate::swarm::members::ensure_registered(&state).await; crate::swarm::stability::tick(&state).await; crate::swarm::stats::measure_saved_size(&state); |
