mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-11-25 03:32:19 +00:00
Kademlia Contact Removal
- Contact removal now working well, we only do removal when we need to get in touch with the contact for some reason. - Replacement cache is now setup
This commit is contained in:
parent
fa47aceda9
commit
b1bfba6d93
@ -284,9 +284,9 @@ public class ContentLookupOperation implements Operation, Receiver
|
|||||||
throw new UnknownMessageException("Unknown comm: " + comm);
|
throw new UnknownMessageException("Unknown comm: " + comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark this node as failed */
|
/* Mark this node as failed and inform the routing table that it's unresponsive */
|
||||||
this.nodes.put(n, FAILED);
|
this.nodes.put(n, FAILED);
|
||||||
this.localNode.getRoutingTable().remove(n);
|
this.localNode.getRoutingTable().setUnresponsiveContact(n);
|
||||||
this.messagesTransiting.remove(comm);
|
this.messagesTransiting.remove(comm);
|
||||||
|
|
||||||
this.askNodesorFinish();
|
this.askNodesorFinish();
|
||||||
|
@ -303,9 +303,9 @@ public class NodeLookupOperation implements Operation, Receiver
|
|||||||
throw new UnknownMessageException("Unknown comm: " + comm);
|
throw new UnknownMessageException("Unknown comm: " + comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark this node as failed */
|
/* Mark this node as failed and inform the routing table that it is unresponsive */
|
||||||
this.nodes.put(n, FAILED);
|
this.nodes.put(n, FAILED);
|
||||||
this.localNode.getRoutingTable().remove(n);
|
this.localNode.getRoutingTable().setUnresponsiveContact(n);
|
||||||
this.messagesTransiting.remove(comm);
|
this.messagesTransiting.remove(comm);
|
||||||
|
|
||||||
this.askNodesorFinish();
|
this.askNodesorFinish();
|
||||||
|
@ -48,15 +48,19 @@ public interface Bucket
|
|||||||
* Remove a contact from this bucket
|
* Remove a contact from this bucket
|
||||||
*
|
*
|
||||||
* @param c The contact to remove
|
* @param c The contact to remove
|
||||||
|
*
|
||||||
|
* @return Boolean whether the removal was successful.
|
||||||
*/
|
*/
|
||||||
public void removeContact(Contact c);
|
public boolean removeContact(Contact c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the contact object related to a node from this bucket
|
* Remove the contact object related to a node from this bucket
|
||||||
*
|
*
|
||||||
* @param n The node of the contact to remove
|
* @param n The node of the contact to remove
|
||||||
|
*
|
||||||
|
* @return Boolean whether the removal was successful.
|
||||||
*/
|
*/
|
||||||
public void removeNode(Node n);
|
public boolean removeNode(Node n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts the number of contacts in this bucket.
|
* Counts the number of contacts in this bucket.
|
||||||
|
@ -2,8 +2,8 @@ package kademlia.routing;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import kademlia.core.KadConfiguration;
|
||||||
import kademlia.node.Node;
|
import kademlia.node.Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,10 +19,12 @@ public class KadBucket implements Bucket
|
|||||||
private final int depth;
|
private final int depth;
|
||||||
|
|
||||||
/* Contacts stored in this routing table */
|
/* Contacts stored in this routing table */
|
||||||
private final Map<Contact, Contact> contacts;
|
private final TreeMap<Contact, Contact> contacts;
|
||||||
|
|
||||||
/* A set of last seen contacts that can replace any current contact that is unresponsive */
|
/* A set of last seen contacts that can replace any current contact that is unresponsive */
|
||||||
private final Map<Contact, Contact> replacementCache;
|
private final TreeMap<Contact, Contact> replacementCache;
|
||||||
|
|
||||||
|
private KadConfiguration config;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -31,17 +33,18 @@ public class KadBucket implements Bucket
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param depth How deep in the routing tree is this bucket
|
* @param depth How deep in the routing tree is this bucket
|
||||||
|
* @param config
|
||||||
*/
|
*/
|
||||||
public KadBucket(int depth)
|
public KadBucket(int depth, KadConfiguration config)
|
||||||
{
|
{
|
||||||
this.depth = depth;
|
this.depth = depth;
|
||||||
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(Contact c)
|
public void insert(Contact c)
|
||||||
{
|
{
|
||||||
/* @todo Check if the bucket is filled already and handle the situation */
|
|
||||||
if (this.contacts.containsKey(c))
|
if (this.contacts.containsKey(c))
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -54,7 +57,16 @@ public class KadBucket implements Bucket
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
contacts.put(c, c);
|
/* If the bucket is filled, we 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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contacts.put(c, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,15 +89,31 @@ public class KadBucket implements Bucket
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeContact(Contact c)
|
public boolean removeContact(Contact c)
|
||||||
{
|
{
|
||||||
|
/* If the contact does not exist, then we failed to remove it */
|
||||||
|
if (!this.contacts.containsKey(c))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this.contacts.remove(c);
|
this.contacts.remove(c);
|
||||||
|
|
||||||
|
/* If there are replacement contacts in the replacement cache, lets put them into the bucket */
|
||||||
|
if (!this.replacementCache.isEmpty())
|
||||||
|
{
|
||||||
|
Contact replacement = this.replacementCache.firstKey();
|
||||||
|
this.contacts.put(replacement, replacement);
|
||||||
|
this.replacementCache.remove(replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeNode(Node n)
|
public boolean removeNode(Node n)
|
||||||
{
|
{
|
||||||
this.removeContact(new Contact(n));
|
return this.removeContact(new Contact(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,6 +134,26 @@ public class KadBucket implements Bucket
|
|||||||
return (this.contacts.isEmpty()) ? new ArrayList<>() : new ArrayList<>(this.contacts.values());
|
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 insertIntoCache(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())
|
||||||
|
{
|
||||||
|
this.replacementCache.remove(this.replacementCache.lastKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.replacementCache.put(c, c);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@ public class RoutingTable
|
|||||||
this.buckets = new Bucket[NodeId.ID_LENGTH];
|
this.buckets = new Bucket[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);
|
buckets[i] = new KadBucket(i, this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,22 +64,6 @@ public class RoutingTable
|
|||||||
this.buckets[this.getBucketId(n.getNodeId())].insert(n);
|
this.buckets[this.getBucketId(n.getNodeId())].insert(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a node from the routing table.
|
|
||||||
*
|
|
||||||
* @param n The node to remove
|
|
||||||
*/
|
|
||||||
public final void remove(Node n)
|
|
||||||
{
|
|
||||||
int bucketId = this.getBucketId(n.getNodeId());
|
|
||||||
|
|
||||||
/* If the bucket has the contact, remove it */
|
|
||||||
if (this.buckets[bucketId].containsNode(n))
|
|
||||||
{
|
|
||||||
this.buckets[bucketId].removeNode(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the bucket ID in which a given node should be placed; the bucketId is computed based on how far the node is away from the Local Node.
|
* Compute the bucket ID in which a given node should be placed; the bucketId is computed based on how far the node is away from the Local Node.
|
||||||
*
|
*
|
||||||
@ -247,14 +231,27 @@ public class RoutingTable
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Unresponsive contacts: ");
|
|
||||||
for (Node n : contacts)
|
for (Node n : contacts)
|
||||||
{
|
{
|
||||||
System.out.println(n);
|
this.setUnresponsiveContact(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used by operations to notify the routing table of any contacts that have been unresponsive.
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
*/
|
||||||
|
public synchronized void setUnresponsiveContact(Node n)
|
||||||
|
{
|
||||||
|
int bucketId = this.getBucketId(n.getNodeId());
|
||||||
|
|
||||||
|
//System.out.println(this.localNode + " Removing unresponsive node " + n);
|
||||||
|
|
||||||
|
/* Remove the contact from the bucket */
|
||||||
|
this.buckets[bucketId].removeNode(n);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized final String toString()
|
public synchronized final String toString()
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package kademlia.tests;
|
package kademlia.tests;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Scanner;
|
||||||
import kademlia.KademliaNode;
|
import kademlia.KademliaNode;
|
||||||
import kademlia.dht.KadContent;
|
import kademlia.dht.KadContent;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
@ -14,33 +15,32 @@ import kademlia.node.NodeId;
|
|||||||
public class RoutingTableStateTesting
|
public class RoutingTableStateTesting
|
||||||
{
|
{
|
||||||
|
|
||||||
KademliaNode kad0, kad1, kad2, kad3, kad4, kad5, kad6, kad7, kad8, kad9;
|
KademliaNode[] kads;
|
||||||
|
|
||||||
|
public int numKads = 10;
|
||||||
|
|
||||||
public RoutingTableStateTesting()
|
public RoutingTableStateTesting()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/* Setting up 2 Kad networks */
|
/* Setting up Kad networks */
|
||||||
kad0 = new KademliaNode("user0", new NodeId("HRF456789SD584567460"), 1334);
|
kads = new KademliaNode[numKads];
|
||||||
kad1 = new KademliaNode("user1", new NodeId("ASF456789475DS567461"), 1209);
|
|
||||||
kad2 = new KademliaNode("user2", new NodeId("AFG45678947584567462"), 4585);
|
|
||||||
kad3 = new KademliaNode("user3", new NodeId("FSF45J38947584567463"), 8104);
|
|
||||||
kad4 = new KademliaNode("user4", new NodeId("ASF45678947584567464"), 8335);
|
|
||||||
kad5 = new KademliaNode("user5", new NodeId("GHF4567894DR84567465"), 13345);
|
|
||||||
kad6 = new KademliaNode("user6", new NodeId("ASF45678947584567466"), 12049);
|
|
||||||
kad7 = new KademliaNode("user7", new NodeId("AE345678947584567467"), 14585);
|
|
||||||
kad8 = new KademliaNode("user8", new NodeId("ASAA5678947584567468"), 18104);
|
|
||||||
kad9 = new KademliaNode("user9", new NodeId("ASF456789475845674U9"), 18335);
|
|
||||||
|
|
||||||
kad1.bootstrap(kad0.getNode());
|
kads[0] = new KademliaNode("user0", new NodeId("HRF456789SD584567460"), 1334);
|
||||||
kad2.bootstrap(kad0.getNode());
|
kads[1] = new KademliaNode("user1", new NodeId("ASF456789475DS567461"), 1209);
|
||||||
kad3.bootstrap(kad0.getNode());
|
kads[2] = new KademliaNode("user2", new NodeId("AFG45678947584567462"), 4585);
|
||||||
kad4.bootstrap(kad0.getNode());
|
kads[3] = new KademliaNode("user3", new NodeId("FSF45J38947584567463"), 8104);
|
||||||
kad5.bootstrap(kad0.getNode());
|
kads[4] = new KademliaNode("user4", new NodeId("ASF45678947584567464"), 8335);
|
||||||
kad6.bootstrap(kad0.getNode());
|
kads[5] = new KademliaNode("user5", new NodeId("GHF4567894DR84567465"), 13345);
|
||||||
kad7.bootstrap(kad0.getNode());
|
kads[6] = new KademliaNode("user6", new NodeId("ASF45678947584567466"), 12049);
|
||||||
kad8.bootstrap(kad0.getNode());
|
kads[7] = new KademliaNode("user7", new NodeId("AE345678947584567467"), 14585);
|
||||||
kad9.bootstrap(kad0.getNode());
|
kads[8] = new KademliaNode("user8", new NodeId("ASAA5678947584567468"), 18104);
|
||||||
|
kads[9] = new KademliaNode("user9", new NodeId("ASF456789475845674U9"), 18335);
|
||||||
|
|
||||||
|
for (int i = 1; i < numKads; i++)
|
||||||
|
{
|
||||||
|
kads[i].bootstrap(kads[0].getNode());
|
||||||
|
}
|
||||||
|
|
||||||
/* Lets shut down a node and then try putting a content on the network. We'll then see how the un-responsive contacts work */
|
/* Lets shut down a node and then try putting a content on the network. We'll then see how the un-responsive contacts work */
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ public class RoutingTableStateTesting
|
|||||||
DHTContentImpl c = null;
|
DHTContentImpl c = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
|
c = new DHTContentImpl(owner.getOwnerId(), "Some Data");
|
||||||
owner.put(c);
|
owner.put(c);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -79,43 +79,71 @@ public class RoutingTableStateTesting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void printRoutingTable(int kadId)
|
||||||
|
{
|
||||||
|
System.out.println(kads[kadId].getRoutingTable());
|
||||||
|
}
|
||||||
|
|
||||||
public void printRoutingTables()
|
public void printRoutingTables()
|
||||||
{
|
{
|
||||||
System.out.println(kad0.getRoutingTable());
|
for (int i = 0; i < numKads; i++)
|
||||||
System.out.println(kad1.getRoutingTable());
|
{
|
||||||
System.out.println(kad2.getRoutingTable());
|
this.printRoutingTable(i);
|
||||||
System.out.println(kad3.getRoutingTable());
|
}
|
||||||
System.out.println(kad4.getRoutingTable());
|
}
|
||||||
System.out.println(kad5.getRoutingTable());
|
|
||||||
System.out.println(kad6.getRoutingTable());
|
public void printStorage(int kadId)
|
||||||
System.out.println(kad7.getRoutingTable());
|
{
|
||||||
System.out.println(kad8.getRoutingTable());
|
System.out.println(kads[kadId].getDHT());
|
||||||
System.out.println(kad9.getRoutingTable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printStorage()
|
public void printStorage()
|
||||||
{
|
{
|
||||||
System.out.println(kad0.getDHT());
|
for (int i = 0; i < numKads; i++)
|
||||||
System.out.println(kad1.getDHT());
|
{
|
||||||
System.out.println(kad2.getDHT());
|
this.printStorage(i);
|
||||||
System.out.println(kad3.getDHT());
|
}
|
||||||
System.out.println(kad4.getDHT());
|
|
||||||
System.out.println(kad5.getDHT());
|
|
||||||
System.out.println(kad6.getDHT());
|
|
||||||
System.out.println(kad7.getDHT());
|
|
||||||
System.out.println(kad8.getDHT());
|
|
||||||
System.out.println(kad9.getDHT());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
|
|
||||||
RoutingTableStateTesting rtss = new RoutingTableStateTesting();
|
RoutingTableStateTesting rtss = new RoutingTableStateTesting();
|
||||||
rtss.printRoutingTables();
|
|
||||||
|
|
||||||
/* Lets shut down a node to test the node removal operation */
|
try
|
||||||
rtss.shutdownKad(rtss.kad3);
|
{
|
||||||
|
rtss.printRoutingTables();
|
||||||
|
|
||||||
rtss.putContent("Content owned by kad0", rtss.kad0);
|
/* Lets shut down a node to test the node removal operation */
|
||||||
rtss.printStorage();
|
rtss.shutdownKad(rtss.kads[3]);
|
||||||
|
|
||||||
|
rtss.putContent("Content owned by kad0", rtss.kads[0]);
|
||||||
|
rtss.printStorage();
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
/* kad3 should be removed from their routing tables by now. */
|
||||||
|
rtss.printRoutingTables();
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Scanner sc = new Scanner(System.in);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
System.out.println("\n\n ************************* Options **************************** \n");
|
||||||
|
System.out.println("1 i - Print routing table of node i");
|
||||||
|
int val1 = sc.nextInt();
|
||||||
|
int val2 = sc.nextInt();
|
||||||
|
|
||||||
|
switch (val1)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
rtss.printRoutingTable(val2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user