Routing Table Contact Management

- Added last seen data to contact
- Contacts are not sorted by lastSeen
- Contact updating last seen time is handled

Built a simulation to test the contact last seen updates
This commit is contained in:
Joshua Kissoon 2014-04-26 21:26:02 +05:30
parent 6253ad0ca6
commit 4fab4320df
6 changed files with 153 additions and 18 deletions

View File

@ -10,7 +10,7 @@ import java.io.File;
public class DefaultConfiguration implements KadConfiguration public class DefaultConfiguration implements KadConfiguration
{ {
private final static long RESTORE_INTERVAL = 10 * 1000; // Default at 1 hour private final static long RESTORE_INTERVAL = 1000 * 1000; // Default at 1 hour
private final static long RESPONSE_TIMEOUT = 1500; private final static long RESPONSE_TIMEOUT = 1500;
private final static long OPERATION_TIMEOUT = 3000; private final static long OPERATION_TIMEOUT = 3000;
private final static int CONCURRENCY = 10; private final static int CONCURRENCY = 10;

View File

@ -7,23 +7,67 @@ import kademlia.node.Node;
* *
* Contacts are used instead of nodes because more information is needed than just the node information. * Contacts are used instead of nodes because more information is needed than just the node information.
* - Information such as * - Information such as
* -- Last alive time * -- Last seen time
* *
* @author Joshua Kissoon * @author Joshua Kissoon
* @since 20140425 * @since 20140425
* @updated 20140426
*/ */
public class Contact public class Contact implements Comparable<Contact>
{ {
private final Node n; private final Node n;
private long lastSeen;
/**
* Create a contact object
*
* @param n The node associated with this contact
*/
public Contact(Node n) public Contact(Node n)
{ {
this.n = n; this.n = n;
this.lastSeen = System.currentTimeMillis() / 1000L;
} }
public Node getNode() public Node getNode()
{ {
return this.n; return this.n;
} }
/**
* When a Node sees a contact a gain, the Node will want to update that it's seen recently,
* this method updates the last seen timestamp for this contact.
*/
public void setSeenNow()
{
this.lastSeen = System.currentTimeMillis() / 1000L;
}
/**
* When last was this contact seen?
*
* @return long The last time this contact was seen.
*/
public long lastSeen()
{
return this.lastSeen;
}
public boolean equals(Contact c)
{
return c.getNode().equals(this.getNode());
}
@Override
public int compareTo(Contact o)
{
if (this.getNode().equals(o.getNode()))
{
return 0;
}
return (this.lastSeen() > o.lastSeen()) ? 1 : -1;
}
} }

View File

@ -0,0 +1,34 @@
package kademlia.routing;
import java.util.Comparator;
/**
* A Comparator to compare 2 contacts by their last seen time
*
* @author Joshua Kissoon
* @since 20140426
*/
public class ContactLastSeenComparator implements Comparator<Contact>
{
/**
* Compare two contacts to determine their order in the Bucket,
* Contacts are ordered by their last seen timestamp.
*
* @param c1 Contact 1
* @param c2 Contact 2
*/
@Override
public int compare(Contact c1, Contact c2)
{
if (c1.getNode().equals(c2.getNode()))
{
return 0;
}
else
{
/* We may have 2 different contacts with same last seen values so we can't return 0 here */
return c1.lastSeen() > c2.lastSeen() ? 1 : -1;
}
}
}

View File

@ -1,11 +1,10 @@
package kademlia.routing; package kademlia.routing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import kademlia.node.Node; import kademlia.node.Node;
import kademlia.node.NodeId;
/** /**
* A bucket in the Kademlia routing table * A bucket in the Kademlia routing table
@ -17,11 +16,11 @@ public class KadBucket implements Bucket
{ {
private final int depth; private final int depth;
private final Map<NodeId, Contact> contacts; private final Map<Contact, Contact> contacts;
{ {
contacts = new HashMap<>(); contacts = new TreeMap<>(new ContactLastSeenComparator());
} }
/** /**
@ -36,15 +35,19 @@ public class KadBucket implements Bucket
public void insert(Contact c) public void insert(Contact c)
{ {
/* @todo Check if the bucket is filled already and handle the situation */ /* @todo Check if the bucket is filled already and handle the situation */
/* Check if the contact is already in the bucket */ if (this.contacts.containsKey(c))
if (this.contacts.containsKey(c.getNode().getNodeId()))
{ {
/* @todo If it is, then move it to the front */ /**
/* @todo Possibly use a doubly linked list instead of an ArrayList */ * 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 else
{ {
contacts.put(c.getNode().getNodeId(), c); contacts.put(c, c);
} }
} }
@ -57,25 +60,25 @@ public class KadBucket implements Bucket
@Override @Override
public boolean containsContact(Contact c) public boolean containsContact(Contact c)
{ {
return this.contacts.containsKey(c.getNode().getNodeId()); return this.contacts.containsKey(c);
} }
@Override @Override
public boolean containsNode(Node n) public boolean containsNode(Node n)
{ {
return this.contacts.containsKey(n.getNodeId()); return this.containsContact(new Contact(n));
} }
@Override @Override
public void removeContact(Contact c) public void removeContact(Contact c)
{ {
this.contacts.remove(c.getNode().getNodeId()); this.contacts.remove(c);
} }
@Override @Override
public void removeNode(Node n) public void removeNode(Node n)
{ {
this.contacts.remove(n.getNodeId()); this.removeContact(new Contact(n));
} }
@Override @Override

View File

@ -45,7 +45,7 @@ public class RoutingTable
* *
* @param c The contact to add * @param c The contact to add
*/ */
public final void insert(Contact c) public synchronized final void insert(Contact c)
{ {
this.buckets[this.getBucketId(c.getNode().getNodeId())].insert(c); this.buckets[this.getBucketId(c.getNode().getNodeId())].insert(c);
} }
@ -55,7 +55,7 @@ public class RoutingTable
* *
* @param n The node to add * @param n The node to add
*/ */
public final void insert(Node n) public synchronized final void insert(Node n)
{ {
this.buckets[this.getBucketId(n.getNodeId())].insert(n); this.buckets[this.getBucketId(n.getNodeId())].insert(n);
} }

View File

@ -0,0 +1,54 @@
package kademlia.tests;
import kademlia.Kademlia;
import kademlia.node.NodeId;
import kademlia.routing.RoutingTable;
/**
* Testing how the routing table works and checking if everything works properly
*
* @author Joshua Kissoon
* @since 20140426
*/
public class RoutingTableSimulation
{
public RoutingTableSimulation()
{
try
{
/* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567463"), 12049);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASF45678947584567464"), 4585);
Kademlia kad3 = new Kademlia("Shameer", new NodeId("ASF45678947584567465"), 8104);
Kademlia kad4 = new Kademlia("Lokesh", new NodeId("ASF45678947584567466"), 8335);
Kademlia kad5 = new Kademlia("Chandu", new NodeId("ASF45678947584567467"), 13345);
RoutingTable rt = kad1.getNode().getRoutingTable();
rt.insert(kad2.getNode());
rt.insert(kad3.getNode());
rt.insert(kad4.getNode());
System.out.println(rt);
rt.insert(kad5.getNode());
System.out.println(rt);
rt.insert(kad3.getNode());
System.out.println(rt);
}
catch (IllegalStateException e)
{
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new RoutingTableSimulation();
}
}