Renamed the bucket classes and interface to clear up things

This commit is contained in:
Joshua Kissoon 2014-05-01 14:42:21 +05:30
parent 1e6b9f2e38
commit fa242fad6a
4 changed files with 282 additions and 282 deletions

View File

@ -1,87 +0,0 @@
package kademlia.routing;
import java.util.List;
import kademlia.node.Node;
/**
* A bucket used to store Contacts in the routing table.
*
* @author Joshua Kissoon
* @created 20140215
*/
public interface Bucket
{
/**
* Adds a contact to the bucket
*
* @param c the new contact
*/
public void insert(Contact c);
/**
* Create a new contact and insert it into the bucket.
*
* @param n The node to create the contact from
*/
public void insert(Node n);
/**
* Checks if this bucket contain a contact
*
* @param c The contact to check for
*
* @return boolean
*/
public boolean containsContact(Contact c);
/**
* Checks if this bucket contain a node
*
* @param n The node to check for
*
* @return boolean
*/
public boolean containsNode(Node n);
/**
* 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
*
* @return Boolean whether the removal was successful.
*/
public boolean removeContact(Contact c);
/**
* Remove the contact object related to a node from this bucket
*
* @param n The node of the contact to remove
*
* @return Boolean whether the removal was successful.
*/
public boolean removeNode(Node n);
/**
* Counts the number of contacts in this bucket.
*
* @return Integer The number of contacts in this bucket
*/
public int numContacts();
/**
* @return Integer The depth of this bucket in the RoutingTable
*/
public int getDepth();
/**
* @return An Iterable structure with all contacts in this bucket
*/
public List<Contact> getContacts();
}

View File

@ -1,210 +1,87 @@
package kademlia.routing; package kademlia.routing;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.TreeMap;
import kademlia.core.KadConfiguration;
import kademlia.node.Node; import kademlia.node.Node;
/** /**
* A bucket in the Kademlia routing table * A bucket used to store Contacts in the routing table.
* *
* @author Joshua Kissoon * @author Joshua Kissoon
* @created 20140215 * @created 20140215
*/ */
public class KadBucket implements Bucket public interface KadBucket
{ {
/* How deep is this bucket in the Routing Table */
private final int depth;
/* Contacts stored in this routing table */
private final TreeMap<Contact, Contact> contacts;
/* A set of last seen contacts that can replace any current contact that is unresponsive */
private final TreeMap<Contact, Contact> replacementCache;
private KadConfiguration config;
{
contacts = new TreeMap<>(new ContactLastSeenComparator());
replacementCache = new TreeMap<>(new ContactLastSeenComparator());
}
/** /**
* @param depth How deep in the routing tree is this bucket * Adds a contact to the bucket
* @param config *
* @param c the new contact
*/ */
public KadBucket(int depth, KadConfiguration config) public void insert(Contact c);
{
this.depth = depth;
this.config = config;
}
@Override
public void insert(Contact c)
{
if (this.contacts.containsKey(c))
{
/**
* If the contact is already in the bucket, lets update that we've seen it
* We need to remove and re-add the contact to get the Sorted Set to update sort order
*/
Contact tmp = this.contacts.remove(c);
tmp.setSeenNow();
this.contacts.put(tmp, tmp);
}
else
{
/* If the bucket is filled, so put the contacts in the replacement cache */
if (contacts.size() >= this.config.k())
{
/* 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
{
contacts.put(c, c);
}
}
}
@Override
public void insert(Node n)
{
this.insert(new Contact(n));
}
@Override
public boolean containsContact(Contact c)
{
return this.contacts.containsKey(c);
}
@Override
public boolean containsNode(Node n)
{
return this.containsContact(new Contact(n));
}
@Override
public boolean removeContact(Contact c)
{
/* If the contact does not exist, then we failed to remove it */
if (!this.contacts.containsKey(c))
{
return false;
}
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;
}
@Override
public boolean removeNode(Node n)
{
return this.removeContact(new Contact(n));
}
@Override
public int numContacts()
{
return this.contacts.size();
}
@Override
public int getDepth()
{
return this.depth;
}
@Override
public synchronized List<Contact> getContacts()
{
return (this.contacts.isEmpty()) ? new ArrayList<>() : new ArrayList<>(this.contacts.values());
}
/** /**
* When the bucket is filled, we keep extra contacts in the replacement cache. * Create a new contact and insert it into the bucket.
*
* @param n The node to create the contact from
*/ */
private void insertIntoReplacementCache(Contact c) public void insert(Node n);
{
/* Just return if this contact is already in our replacement cache */
if (this.replacementCache.containsKey(c))
{
/** /**
* If the contact is already in the bucket, lets update that we've seen it * Checks if this bucket contain a contact
* We need to remove and re-add the contact to get the Sorted Set to update sort order *
* @param c The contact to check for
*
* @return boolean
*/ */
Contact tmp = this.replacementCache.remove(c); public boolean containsContact(Contact c);
tmp.setSeenNow();
this.replacementCache.put(tmp, tmp);
return;
}
/* if our cache is filled, we remove the least recently seen contact */ /**
if (this.replacementCache.size() > this.config.k()) * Checks if this bucket contain a node
{ *
this.replacementCache.remove(this.replacementCache.lastKey()); * @param n The node to check for
} *
* @return boolean
*/
public boolean containsNode(Node n);
this.replacementCache.put(c, c); /**
} * 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
*
* @return Boolean whether the removal was successful.
*/
public boolean removeContact(Contact c);
@Override /**
public String toString() * Remove the contact object related to a node from this bucket
{ *
StringBuilder sb = new StringBuilder("Bucket at depth: "); * @param n The node of the contact to remove
sb.append(this.depth); *
sb.append("\n Nodes: \n"); * @return Boolean whether the removal was successful.
for (Contact n : this.contacts.values()) */
{ public boolean removeNode(Node n);
sb.append("Node: ");
sb.append(n.getNode().getNodeId().toString());
sb.append("\n");
}
return sb.toString(); /**
} * Counts the number of contacts in this bucket.
*
* @return Integer The number of contacts in this bucket
*/
public int numContacts();
/**
* @return Integer The depth of this bucket in the RoutingTable
*/
public int getDepth();
/**
* @return An Iterable structure with all contacts in this bucket
*/
public List<Contact> getContacts();
} }

View File

@ -0,0 +1,210 @@
package kademlia.routing;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import kademlia.core.KadConfiguration;
import kademlia.node.Node;
/**
* A bucket in the Kademlia routing table
*
* @author Joshua Kissoon
* @created 20140215
*/
public class KadBucketImpl implements KadBucket
{
/* How deep is this bucket in the Routing Table */
private final int depth;
/* Contacts stored in this routing table */
private final TreeMap<Contact, Contact> contacts;
/* A set of last seen contacts that can replace any current contact that is unresponsive */
private final TreeMap<Contact, Contact> replacementCache;
private KadConfiguration config;
{
contacts = new TreeMap<>(new ContactLastSeenComparator());
replacementCache = new TreeMap<>(new ContactLastSeenComparator());
}
/**
* @param depth How deep in the routing tree is this bucket
* @param config
*/
public KadBucketImpl(int depth, KadConfiguration config)
{
this.depth = depth;
this.config = config;
}
@Override
public void insert(Contact c)
{
if (this.contacts.containsKey(c))
{
/**
* If the contact is already in the bucket, lets update that we've seen it
* We need to remove and re-add the contact to get the Sorted Set to update sort order
*/
Contact tmp = this.contacts.remove(c);
tmp.setSeenNow();
this.contacts.put(tmp, tmp);
}
else
{
/* If the bucket is filled, so put the contacts in the replacement cache */
if (contacts.size() >= this.config.k())
{
/* 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
{
contacts.put(c, c);
}
}
}
@Override
public void insert(Node n)
{
this.insert(new Contact(n));
}
@Override
public boolean containsContact(Contact c)
{
return this.contacts.containsKey(c);
}
@Override
public boolean containsNode(Node n)
{
return this.containsContact(new Contact(n));
}
@Override
public boolean removeContact(Contact c)
{
/* If the contact does not exist, then we failed to remove it */
if (!this.contacts.containsKey(c))
{
return false;
}
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;
}
@Override
public boolean removeNode(Node n)
{
return this.removeContact(new Contact(n));
}
@Override
public int numContacts()
{
return this.contacts.size();
}
@Override
public int getDepth()
{
return this.depth;
}
@Override
public synchronized List<Contact> getContacts()
{
return (this.contacts.isEmpty()) ? new ArrayList<>() : new ArrayList<>(this.contacts.values());
}
/**
* When the bucket is filled, we keep extra contacts in the replacement cache.
*/
private void insertIntoReplacementCache(Contact c)
{
/* Just return if this contact is already in our replacement cache */
if (this.replacementCache.containsKey(c))
{
/**
* If the contact is already in the bucket, lets update that we've seen it
* We need to remove and re-add the contact to get the Sorted Set to update sort order
*/
Contact tmp = this.replacementCache.remove(c);
tmp.setSeenNow();
this.replacementCache.put(tmp, tmp);
return;
}
/* if our cache is filled, we remove the least recently seen contact */
if (this.replacementCache.size() > this.config.k())
{
this.replacementCache.remove(this.replacementCache.lastKey());
}
this.replacementCache.put(c, c);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("Bucket at depth: ");
sb.append(this.depth);
sb.append("\n Nodes: \n");
for (Contact n : this.contacts.values())
{
sb.append("Node: ");
sb.append(n.getNode().getNodeId().toString());
sb.append("\n");
}
return sb.toString();
}
}

View File

@ -16,7 +16,7 @@ public class RoutingTable
{ {
private final Node localNode; // The current node private final Node localNode; // The current node
private transient Bucket[] buckets; private transient KadBucket[] buckets;
private final KadConfiguration config; private final KadConfiguration config;
@ -37,10 +37,10 @@ public class RoutingTable
*/ */
public final void initialize() public final void initialize()
{ {
this.buckets = new Bucket[NodeId.ID_LENGTH]; this.buckets = new KadBucket[NodeId.ID_LENGTH];
for (int i = 0; i < NodeId.ID_LENGTH; i++) for (int i = 0; i < NodeId.ID_LENGTH; i++)
{ {
buckets[i] = new KadBucket(i, this.config); buckets[i] = new KadBucketImpl(i, this.config);
} }
} }
@ -176,7 +176,7 @@ public class RoutingTable
{ {
List<Node> nodes = new ArrayList<>(); List<Node> nodes = new ArrayList<>();
for (Bucket b : this.buckets) for (KadBucket b : this.buckets)
{ {
for (Contact c : b.getContacts()) for (Contact c : b.getContacts())
{ {
@ -194,7 +194,7 @@ public class RoutingTable
{ {
List<Contact> contacts = new ArrayList<>(); List<Contact> contacts = new ArrayList<>();
for (Bucket b : this.buckets) for (KadBucket b : this.buckets)
{ {
contacts.addAll(b.getContacts()); contacts.addAll(b.getContacts());
} }
@ -205,7 +205,7 @@ public class RoutingTable
/** /**
* @return Bucket[] The buckets in this Kad Instance * @return Bucket[] The buckets in this Kad Instance
*/ */
public final Bucket[] getBuckets() public final KadBucket[] getBuckets()
{ {
return this.buckets; return this.buckets;
} }
@ -215,7 +215,7 @@ public class RoutingTable
* *
* @param buckets * @param buckets
*/ */
public final void setBuckets(Bucket[] buckets) public final void setBuckets(KadBucket[] buckets)
{ {
this.buckets = buckets; this.buckets = buckets;
} }
@ -257,7 +257,7 @@ public class RoutingTable
{ {
StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n"); StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n");
int totalContacts = 0; int totalContacts = 0;
for (Bucket b : this.buckets) for (KadBucket b : this.buckets)
{ {
if (b.numContacts() > 0) if (b.numContacts() > 0)
{ {