aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormurilo ijanc2026-03-25 16:52:03 -0300
committermurilo ijanc2026-03-25 16:52:03 -0300
commit4cff87560ba238ba6eebd16b1465c0ebae2f6ac2 (patch)
treeae9598973520d5cd6d4528f198dec7b9699c0f5e
parentc4076f54c9e66afb73081fd33b4176ba4407a8a5 (diff)
downloadtesseras-dht-4cff87560ba238ba6eebd16b1465c0ebae2f6ac2.tar.gz
Remove stale peers without replacement from routing table
When a peer exceeds STALE_THRESHOLD failures and the replacement cache is empty, remove it outright instead of leaving it in the bucket indefinitely. Prevents phantom peer accumulation in small clusters where the cache rarely fills.
-rw-r--r--src/handlers.rs7
-rw-r--r--src/lib.rs2
-rw-r--r--src/routing.rs19
3 files changed, 16 insertions, 12 deletions
diff --git a/src/handlers.rs b/src/handlers.rs
index f4c5b2c..574aca3 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -849,8 +849,7 @@ impl Node {
.closest
.iter()
.find(|p| {
- q.queried.contains(&p.id)
- && p.id != sender_id
+ q.queried.contains(&p.id) && p.id != sender_id
})
.cloned();
@@ -866,9 +865,7 @@ impl Node {
is_unique: false,
};
if let Err(e) = self.send_store(&peer, &store_msg) {
- log::debug!(
- "Republish-on-access failed: {e}"
- );
+ log::debug!("Republish-on-access failed: {e}");
} else {
log::debug!(
"Republished value to {:?} (nearest without)",
diff --git a/src/lib.rs b/src/lib.rs
index f956f98..1c663d6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -124,5 +124,5 @@ pub use id::NodeId;
pub use nat::NatState;
// Re-export sha2 for downstream crates.
-pub use sha2;
pub use node::Node;
+pub use sha2;
diff --git a/src/routing.rs b/src/routing.rs
index a9b618d..dad9bb5 100644
--- a/src/routing.rs
+++ b/src/routing.rs
@@ -140,10 +140,8 @@ impl KBucket {
/// Add a contact to the replacement cache.
fn add_to_cache(&mut self, peer: PeerInfo) {
// Update if already in cache
- if let Some(pos) = self
- .replacements
- .iter()
- .position(|r| r.id == peer.id)
+ if let Some(pos) =
+ self.replacements.iter().position(|r| r.id == peer.id)
{
self.replacements.remove(pos);
self.replacements.push(peer);
@@ -368,7 +366,9 @@ impl RoutingTable {
/// Record a communication failure for a peer.
/// If the peer becomes stale (exceeds threshold),
/// tries to replace it with a cached contact.
- /// Returns the evicted NodeId if replacement happened.
+ /// If no replacement is available, removes the stale
+ /// peer outright to avoid phantom entries.
+ /// Returns the evicted NodeId if removal happened.
pub fn record_failure(&mut self, id: &NodeId) -> Option<NodeId> {
// Never mark pinned nodes as stale
if self.pinned.contains(id) {
@@ -377,7 +377,14 @@ impl RoutingTable {
let idx = self.bucket_index(id)?;
let became_stale = self.buckets[idx].record_failure(id);
if became_stale {
- self.buckets[idx].try_replace_stale(id)
+ // Try replacement cache first; if empty, just
+ // remove the dead peer so it doesn't linger.
+ let evicted = self.buckets[idx].try_replace_stale(id);
+ if evicted.is_none() {
+ self.remove(id);
+ return Some(*id);
+ }
+ evicted
} else {
None
}