mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-11-22 10:12:19 +00:00
Routing Table Improvement
- Setup the RoutingTable to store contact instead of node - This helps since we'll need more information in the routing to evict contacts, etc
This commit is contained in:
parent
c902ba26ab
commit
21b6667eb8
@ -10,7 +10,7 @@ import java.io.File;
|
|||||||
public class DefaultConfiguration implements KadConfiguration
|
public class DefaultConfiguration implements KadConfiguration
|
||||||
{
|
{
|
||||||
|
|
||||||
private final static long RESTORE_INTERVAL = 60 * 1000; // Default at 1 hour
|
private final static long RESTORE_INTERVAL = 10 * 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;
|
||||||
|
@ -36,7 +36,7 @@ public class KadServer
|
|||||||
/* Server Objects */
|
/* Server Objects */
|
||||||
private final int udpPort;
|
private final int udpPort;
|
||||||
private final DatagramSocket socket;
|
private final DatagramSocket socket;
|
||||||
private boolean isRunning;
|
private transient boolean isRunning;
|
||||||
private final Map<Integer, Receiver> receivers;
|
private final Map<Integer, Receiver> receivers;
|
||||||
private final Timer timer; // Schedule future tasks
|
private final Timer timer; // Schedule future tasks
|
||||||
private final Map<Integer, TimerTask> tasks; // Keep track of scheduled tasks
|
private final Map<Integer, TimerTask> tasks; // Keep track of scheduled tasks
|
||||||
@ -109,7 +109,7 @@ public class KadServer
|
|||||||
{
|
{
|
||||||
if (!isRunning)
|
if (!isRunning)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Kad Server is not running.");
|
throw new IllegalStateException("Kad Server is not running on node " + this.localNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate a random communication ID */
|
/* Generate a random communication ID */
|
||||||
|
@ -4,7 +4,7 @@ import java.util.List;
|
|||||||
import kademlia.node.Node;
|
import kademlia.node.Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bucket used to store Nodes in the routing table.
|
* A bucket used to store Contacts in the routing table.
|
||||||
*
|
*
|
||||||
* @author Joshua Kissoon
|
* @author Joshua Kissoon
|
||||||
* @created 20140215
|
* @created 20140215
|
||||||
@ -13,12 +13,28 @@ public interface Bucket
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new node to the bucket
|
* Adds a contact to the bucket
|
||||||
*
|
*
|
||||||
* @param n the new node
|
* @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);
|
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
|
* Checks if this bucket contain a node
|
||||||
*
|
*
|
||||||
@ -26,21 +42,28 @@ public interface Bucket
|
|||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean containNode(Node n);
|
public boolean containsNode(Node n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a node from this bucket
|
* Remove a contact from this bucket
|
||||||
*
|
*
|
||||||
* @param n The node to remove
|
* @param c The contact to remove
|
||||||
|
*/
|
||||||
|
public void removeContact(Contact c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the contact object related to a node from this bucket
|
||||||
|
*
|
||||||
|
* @param n The node of the contact to remove
|
||||||
*/
|
*/
|
||||||
public void removeNode(Node n);
|
public void removeNode(Node n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts the number of nodes in this bucket.
|
* Counts the number of contacts in this bucket.
|
||||||
*
|
*
|
||||||
* @return Integer The number of nodes in this bucket
|
* @return Integer The number of contacts in this bucket
|
||||||
*/
|
*/
|
||||||
public int numNodes();
|
public int numContacts();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Integer The depth of this bucket in the RoutingTable
|
* @return Integer The depth of this bucket in the RoutingTable
|
||||||
@ -48,7 +71,7 @@ public interface Bucket
|
|||||||
public int getDepth();
|
public int getDepth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return An Iterable structure with all nodes in this bucket
|
* @return An Iterable structure with all contacts in this bucket
|
||||||
*/
|
*/
|
||||||
public List<Node> getNodes();
|
public List<Contact> getContacts();
|
||||||
}
|
}
|
||||||
|
29
src/kademlia/routing/Contact.java
Normal file
29
src/kademlia/routing/Contact.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package kademlia.routing;
|
||||||
|
|
||||||
|
import kademlia.node.Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps information about contacts of the Node; Contacts are stored in the Buckets in the Routing Table.
|
||||||
|
*
|
||||||
|
* Contacts are used instead of nodes because more information is needed than just the node information.
|
||||||
|
* - Information such as
|
||||||
|
* -- Last alive time
|
||||||
|
*
|
||||||
|
* @author Joshua Kissoon
|
||||||
|
* @since 20140425
|
||||||
|
*/
|
||||||
|
public class Contact
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Node n;
|
||||||
|
|
||||||
|
public Contact(Node n)
|
||||||
|
{
|
||||||
|
this.n = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNode()
|
||||||
|
{
|
||||||
|
return this.n;
|
||||||
|
}
|
||||||
|
}
|
@ -17,11 +17,11 @@ public class KadBucket implements Bucket
|
|||||||
{
|
{
|
||||||
|
|
||||||
private final int depth;
|
private final int depth;
|
||||||
private final Map<NodeId, Node> nodes;
|
private final Map<NodeId, Contact> contacts;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
nodes = new HashMap<>();
|
contacts = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,49 +33,55 @@ public class KadBucket implements Bucket
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(Node n)
|
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 */
|
/* Check if the contact is already in the bucket */
|
||||||
if (this.nodes.containsKey(n.getNodeId()))
|
if (this.contacts.containsKey(c.getNode().getNodeId()))
|
||||||
{
|
{
|
||||||
/* @todo If it is, then move it to the front */
|
/* @todo If it is, then move it to the front */
|
||||||
/* @todo Possibly use a doubly linked list instead of an ArrayList */
|
/* @todo Possibly use a doubly linked list instead of an ArrayList */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nodes.put(n.getNodeId(), n);
|
contacts.put(c.getNode().getNodeId(), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this bucket contain a node
|
|
||||||
*
|
|
||||||
* @param n The node to check for
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containNode(Node n)
|
public void insert(Node n)
|
||||||
{
|
{
|
||||||
return this.nodes.containsKey(n.getNodeId());
|
this.insert(new Contact(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsContact(Contact c)
|
||||||
|
{
|
||||||
|
return this.contacts.containsKey(c.getNode().getNodeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsNode(Node n)
|
||||||
|
{
|
||||||
|
return this.contacts.containsKey(n.getNodeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeContact(Contact c)
|
||||||
|
{
|
||||||
|
this.contacts.remove(c.getNode().getNodeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a node from this bucket
|
|
||||||
*
|
|
||||||
* @param n The node to remove
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void removeNode(Node n)
|
public void removeNode(Node n)
|
||||||
{
|
{
|
||||||
this.nodes.remove(n.getNodeId());
|
this.contacts.remove(n.getNodeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int numNodes()
|
public int numContacts()
|
||||||
{
|
{
|
||||||
return this.nodes.size();
|
return this.contacts.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -85,9 +91,9 @@ public class KadBucket implements Bucket
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Node> getNodes()
|
public List<Contact> getContacts()
|
||||||
{
|
{
|
||||||
return new ArrayList<>(this.nodes.values());
|
return new ArrayList<>(this.contacts.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,10 +102,10 @@ public class KadBucket implements Bucket
|
|||||||
StringBuilder sb = new StringBuilder("Bucket at depth: ");
|
StringBuilder sb = new StringBuilder("Bucket at depth: ");
|
||||||
sb.append(this.depth);
|
sb.append(this.depth);
|
||||||
sb.append("\n Nodes: \n");
|
sb.append("\n Nodes: \n");
|
||||||
for (Node n : this.nodes.values())
|
for (Contact n : this.contacts.values())
|
||||||
{
|
{
|
||||||
sb.append("Node: ");
|
sb.append("Node: ");
|
||||||
sb.append(n.getNodeId().toString());
|
sb.append(n.getNode().getNodeId().toString());
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +41,19 @@ public class RoutingTable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new node to the routing table based on how far it is from the LocalNode.
|
* Adds a contact to the routing table based on how far it is from the LocalNode.
|
||||||
*
|
*
|
||||||
* @param n The contact to add
|
* @param c The contact to add
|
||||||
|
*/
|
||||||
|
public final void insert(Contact c)
|
||||||
|
{
|
||||||
|
this.buckets[this.getBucketId(c.getNode().getNodeId())].insert(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a node to the routing table based on how far it is from the LocalNode.
|
||||||
|
*
|
||||||
|
* @param n The node to add
|
||||||
*/
|
*/
|
||||||
public final void insert(Node n)
|
public final void insert(Node n)
|
||||||
{
|
{
|
||||||
@ -60,7 +70,7 @@ public class RoutingTable
|
|||||||
int bucketId = this.getBucketId(n.getNodeId());
|
int bucketId = this.getBucketId(n.getNodeId());
|
||||||
|
|
||||||
/* If the bucket has the contact, remove it */
|
/* If the bucket has the contact, remove it */
|
||||||
if (this.buckets[bucketId].containNode(n))
|
if (this.buckets[bucketId].containsNode(n))
|
||||||
{
|
{
|
||||||
this.buckets[bucketId].removeNode(n);
|
this.buckets[bucketId].removeNode(n);
|
||||||
}
|
}
|
||||||
@ -97,11 +107,11 @@ public class RoutingTable
|
|||||||
int bucketIndex = this.getBucketId(target);
|
int bucketIndex = this.getBucketId(target);
|
||||||
|
|
||||||
/* Add the contacts from this bucket to the return contacts */
|
/* Add the contacts from this bucket to the return contacts */
|
||||||
for (Node c : this.buckets[bucketIndex].getNodes())
|
for (Contact c : this.buckets[bucketIndex].getContacts())
|
||||||
{
|
{
|
||||||
if (closest.size() < numNodesRequired)
|
if (closest.size() < numNodesRequired)
|
||||||
{
|
{
|
||||||
closest.add(c);
|
closest.add(c.getNode());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -120,11 +130,11 @@ public class RoutingTable
|
|||||||
*/
|
*/
|
||||||
for (int i = 1; (bucketIndex - i) >= 0; i++)
|
for (int i = 1; (bucketIndex - i) >= 0; i++)
|
||||||
{
|
{
|
||||||
for (Node c : this.buckets[bucketIndex - i].getNodes())
|
for (Contact c : this.buckets[bucketIndex - i].getContacts())
|
||||||
{
|
{
|
||||||
if (closest.size() < numNodesRequired)
|
if (closest.size() < numNodesRequired)
|
||||||
{
|
{
|
||||||
closest.add(c);
|
closest.add(c.getNode());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -149,11 +159,11 @@ public class RoutingTable
|
|||||||
*/
|
*/
|
||||||
for (int i = 1; (bucketIndex + i) < NodeId.ID_LENGTH; i++)
|
for (int i = 1; (bucketIndex + i) < NodeId.ID_LENGTH; i++)
|
||||||
{
|
{
|
||||||
for (Node c : this.buckets[bucketIndex + i].getNodes())
|
for (Contact c : this.buckets[bucketIndex + i].getContacts())
|
||||||
{
|
{
|
||||||
if (closest.size() < numNodesRequired)
|
if (closest.size() < numNodesRequired)
|
||||||
{
|
{
|
||||||
closest.add(c);
|
closest.add(c.getNode());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -180,12 +190,30 @@ public class RoutingTable
|
|||||||
|
|
||||||
for (Bucket b : this.buckets)
|
for (Bucket b : this.buckets)
|
||||||
{
|
{
|
||||||
nodes.addAll(b.getNodes());
|
for (Contact c : b.getContacts())
|
||||||
|
{
|
||||||
|
nodes.add(c.getNode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List A List of all Nodes in this RoutingTable
|
||||||
|
*/
|
||||||
|
public final List getAllContacts()
|
||||||
|
{
|
||||||
|
List<Contact> contacts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Bucket b : this.buckets)
|
||||||
|
{
|
||||||
|
contacts.addAll(b.getContacts());
|
||||||
|
}
|
||||||
|
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Bucket[] The buckets in this Kad Instance
|
* @return Bucket[] The buckets in this Kad Instance
|
||||||
*/
|
*/
|
||||||
@ -210,12 +238,12 @@ public class RoutingTable
|
|||||||
StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n");
|
StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n");
|
||||||
for (Bucket b : this.buckets)
|
for (Bucket b : this.buckets)
|
||||||
{
|
{
|
||||||
if (b.numNodes() > 0)
|
if (b.numContacts() > 0)
|
||||||
{
|
{
|
||||||
sb.append("# nodes in Bucket with depth ");
|
sb.append("# nodes in Bucket with depth ");
|
||||||
sb.append(b.getDepth());
|
sb.append(b.getDepth());
|
||||||
sb.append(": ");
|
sb.append(": ");
|
||||||
sb.append(b.numNodes());
|
sb.append(b.numContacts());
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
sb.append(b.toString());
|
sb.append(b.toString());
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
|
@ -79,7 +79,10 @@ public class SaveStateTest
|
|||||||
Kademlia kadR2 = Kademlia.loadFromFile("JoshuaK");
|
Kademlia kadR2 = Kademlia.loadFromFile("JoshuaK");
|
||||||
System.out.println(kadR2);
|
System.out.println(kadR2);
|
||||||
}
|
}
|
||||||
|
catch (IllegalStateException e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -13,6 +13,7 @@ import kademlia.routing.RoutingTable;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import kademlia.node.Node;
|
import kademlia.node.Node;
|
||||||
|
import kademlia.routing.Contact;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A KadSerializer that serializes routing tables to JSON format
|
* A KadSerializer that serializes routing tables to JSON format
|
||||||
@ -43,6 +44,10 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
|||||||
|
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
|
|
||||||
|
Type contactCollectionType = new TypeToken<List<Contact>>()
|
||||||
|
{
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
gson = new Gson();
|
gson = new Gson();
|
||||||
@ -58,15 +63,11 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
|||||||
/* Write the basic RoutingTable */
|
/* Write the basic RoutingTable */
|
||||||
gson.toJson(data, RoutingTable.class, writer);
|
gson.toJson(data, RoutingTable.class, writer);
|
||||||
|
|
||||||
/* Now Store the Nodes */
|
/* Now Store the Contacts */
|
||||||
Type collectionType = new TypeToken<List<Node>>()
|
gson.toJson(data.getAllContacts(), contactCollectionType, writer);
|
||||||
{
|
|
||||||
}.getType();
|
|
||||||
gson.toJson(data.getAllNodes(), collectionType, writer);
|
|
||||||
|
|
||||||
writer.endArray();
|
writer.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -80,16 +81,13 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
|||||||
/* Read the basic RoutingTable */
|
/* Read the basic RoutingTable */
|
||||||
RoutingTable tbl = gson.fromJson(reader, RoutingTable.class);
|
RoutingTable tbl = gson.fromJson(reader, RoutingTable.class);
|
||||||
|
|
||||||
/* Now get the nodes and add them back to the RoutingTable */
|
/* Now get the Contacts and add them back to the RoutingTable */
|
||||||
Type collectionType = new TypeToken<List<Node>>()
|
List<Contact> contacts = gson.fromJson(reader, contactCollectionType);
|
||||||
{
|
|
||||||
}.getType();
|
|
||||||
List<Node> nodes = gson.fromJson(reader, collectionType);
|
|
||||||
tbl.initialize();
|
tbl.initialize();
|
||||||
|
|
||||||
for (Node n : nodes)
|
for (Contact c : contacts)
|
||||||
{
|
{
|
||||||
tbl.insert(n);
|
tbl.insert(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.endArray();
|
reader.endArray();
|
||||||
|
Loading…
Reference in New Issue
Block a user