diff --git a/src/kademlia/routing/Bucket.java b/src/kademlia/routing/Bucket.java index 606763b..0e57e72 100644 --- a/src/kademlia/routing/Bucket.java +++ b/src/kademlia/routing/Bucket.java @@ -45,7 +45,13 @@ public interface Bucket public boolean containsNode(Node n); /** - * Remove a contact from this bucket + * Remove a contact from this bucket. + * + * If there are replacement contacts in the replacement cache, + * select the last seen one and put it into the bucket while removing the required contact. + * + * If there are no contacts in the replacement cache, then we just mark the contact requested to be removed as stale. + * Marking as stale would actually be incrementing the stale count of the contact. * * @param c The contact to remove * diff --git a/src/kademlia/routing/Contact.java b/src/kademlia/routing/Contact.java index 3e10b5c..fc0f414 100644 --- a/src/kademlia/routing/Contact.java +++ b/src/kademlia/routing/Contact.java @@ -19,6 +19,15 @@ public class Contact implements Comparable private final Node n; private long lastSeen; + /** + * Stale as described by Kademlia paper page 64 + * When a contact fails to respond, if the replacement cache is empty and there is no replacement for the contact, + * just mark it as stale. + * + * Now when a new contact is added, if the contact is stale, it is removed. + */ + private int staleCount; + /** * Create a contact object * @@ -59,6 +68,22 @@ public class Contact implements Comparable return c.getNode().equals(this.getNode()); } + /** + * Increments the amount of times this count has failed to respond to a request. + */ + public void incrementStaleCount() + { + staleCount++; + } + + /** + * @return Integer Stale count + */ + public int staleCount() + { + return this.staleCount; + } + @Override public int compareTo(Contact o) { diff --git a/src/kademlia/routing/KadBucket.java b/src/kademlia/routing/KadBucket.java index bba298e..32f6c1f 100644 --- a/src/kademlia/routing/KadBucket.java +++ b/src/kademlia/routing/KadBucket.java @@ -57,11 +57,38 @@ public class KadBucket implements Bucket } else { - /* If the bucket is filled, we put the contacts in the replacement cache */ + /* If the bucket is filled, so put the contacts in the replacement cache */ if (contacts.size() >= this.config.k()) { - /* Bucket is filled, place this contact in the replacement cache */ - this.insertIntoCache(c); + /* If the cache is empty, we check if any contacts are stale and replace the stalest one */ + Contact stalest = null; + for (Contact tmp : this.contacts.keySet()) + { + if (tmp.staleCount() > this.config.stale()) + { + /* Contact is stale */ + if (stalest == null) + { + stalest = tmp; + } + else if (tmp.staleCount() > stalest.staleCount()) + { + stalest = tmp; + } + } + } + + /* If we have a stale contact, remove it and add the new contact to the bucket */ + if (stalest != null) + { + this.contacts.remove(stalest); + this.insert(c); + } + else + { + /* No stale contact, lets insert this into replacement cache */ + this.insertIntoReplacementCache(c); + } } else { @@ -97,15 +124,19 @@ public class KadBucket implements Bucket return false; } - this.contacts.remove(c); - - /* If there are replacement contacts in the replacement cache, lets put them into the bucket */ if (!this.replacementCache.isEmpty()) { + /* Replace the contact with one from the replacement cache */ + this.contacts.remove(c); Contact replacement = this.replacementCache.firstKey(); this.contacts.put(replacement, replacement); this.replacementCache.remove(replacement); } + else + { + /* There is no replacement, just increment the contact's stale count */ + this.contacts.get(c).incrementStaleCount(); + } return true; } @@ -137,14 +168,14 @@ public class KadBucket implements Bucket /** * When the bucket is filled, we keep extra contacts in the replacement cache. */ - private void insertIntoCache(Contact c) + private void insertIntoReplacementCache(Contact c) { /* Just return if this contact is already in our replacement cache */ if (this.replacementCache.containsKey(c)) { return; } - + /* if our cache is filled, we remove the least recently seen contact */ if (this.replacementCache.size() > this.config.k()) {