mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-11-22 10:12:19 +00:00
Fixed the bug that was causing replication of content files and StorageEntries. RefreshOperation working well!!
This commit is contained in:
parent
b93133337c
commit
d9fdcc57fd
@ -11,7 +11,7 @@ public class Configuration
|
|||||||
/**
|
/**
|
||||||
* Interval in milliseconds between execution of RestoreOperations.
|
* Interval in milliseconds between execution of RestoreOperations.
|
||||||
* */
|
* */
|
||||||
public static long RESTORE_INTERVAL = 60 * 60 * 1000;
|
public static long RESTORE_INTERVAL = 60 * 1000; // Default at 1 hour
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If no reply received from a node in this period (in milliseconds)
|
* If no reply received from a node in this period (in milliseconds)
|
||||||
@ -37,7 +37,7 @@ public class Configuration
|
|||||||
/**
|
/**
|
||||||
* Bucket size.
|
* Bucket size.
|
||||||
* */
|
* */
|
||||||
public static int K = 5;
|
public static int K = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of replacement cache.
|
* Size of replacement cache.
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import kademlia.core.Configuration;
|
import kademlia.core.Configuration;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.core.GetParameter;
|
||||||
|
import kademlia.exceptions.ContentExistException;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
import kademlia.serializer.JsonSerializer;
|
import kademlia.serializer.JsonSerializer;
|
||||||
|
|
||||||
@ -54,12 +55,19 @@ public class DHT
|
|||||||
public void store(KadContent content) throws IOException
|
public void store(KadContent content) throws IOException
|
||||||
{
|
{
|
||||||
/* Keep track of this content in the entries manager */
|
/* Keep track of this content in the entries manager */
|
||||||
this.entriesManager.put(content);
|
try
|
||||||
|
{
|
||||||
|
StorageEntry sEntry = this.entriesManager.put(content);
|
||||||
|
|
||||||
/* Now we store the content locally in a file */
|
/* Now we store the content locally in a file */
|
||||||
String contentStorageFolder = this.getContentStorageFolderName(content.getKey());
|
String contentStorageFolder = this.getContentStorageFolderName(content.getKey());
|
||||||
DataOutputStream dout = new DataOutputStream(new FileOutputStream(contentStorageFolder + File.separator + content.hashCode() + ".kct"));
|
DataOutputStream dout = new DataOutputStream(new FileOutputStream(contentStorageFolder + File.separator + sEntry.hashCode() + ".kct"));
|
||||||
contentSerializer.write(content, dout);
|
contentSerializer.write(content, dout);
|
||||||
|
}
|
||||||
|
catch (ContentExistException e)
|
||||||
|
{
|
||||||
|
/* Content already exist on the DHT, no need to do anything here */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +110,7 @@ public class DHT
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return this.retrieve(entry.getKey(), entry.getContentHash());
|
return this.retrieve(entry.getKey(), entry.hashCode());
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e)
|
catch (FileNotFoundException e)
|
||||||
{
|
{
|
||||||
@ -133,7 +141,7 @@ public class DHT
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
StorageEntry e = this.entriesManager.get(param);
|
StorageEntry e = this.entriesManager.get(param);
|
||||||
return this.retrieve(e.getKey(), e.getContentHash());
|
return this.retrieve(e.getKey(), e.hashCode());
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e)
|
catch (FileNotFoundException e)
|
||||||
{
|
{
|
||||||
@ -201,7 +209,14 @@ public class DHT
|
|||||||
{
|
{
|
||||||
for (StorageEntry e : ientries)
|
for (StorageEntry e : ientries)
|
||||||
{
|
{
|
||||||
this.entriesManager.put(e);
|
try
|
||||||
|
{
|
||||||
|
this.entriesManager.put(e);
|
||||||
|
}
|
||||||
|
catch (ContentExistException ex)
|
||||||
|
{
|
||||||
|
/* Entry already exist, no need to store it again */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,14 @@ public interface KadContent
|
|||||||
*/
|
*/
|
||||||
public long getCreatedTimestamp();
|
public long getCreatedTimestamp();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each content will have an update timestamp
|
||||||
|
* This allows the DHT to keep only the latest version of a content
|
||||||
|
*
|
||||||
|
* @return long The timestamp of when this content was last updated
|
||||||
|
*/
|
||||||
|
public long getLastUpdatedTimestamp();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The ID of the owner of this content
|
* @return The ID of the owner of this content
|
||||||
*/
|
*/
|
||||||
|
@ -18,6 +18,7 @@ public class StorageEntry
|
|||||||
private final String ownerId;
|
private final String ownerId;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final int contentHash;
|
private final int contentHash;
|
||||||
|
private final long lastUpdated;
|
||||||
|
|
||||||
public StorageEntry(KadContent content)
|
public StorageEntry(KadContent content)
|
||||||
{
|
{
|
||||||
@ -25,6 +26,7 @@ public class StorageEntry
|
|||||||
this.ownerId = content.getOwnerId();
|
this.ownerId = content.getOwnerId();
|
||||||
this.type = content.getType();
|
this.type = content.getType();
|
||||||
this.contentHash = content.hashCode();
|
this.contentHash = content.hashCode();
|
||||||
|
this.lastUpdated = content.getLastUpdatedTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeId getKey()
|
public NodeId getKey()
|
||||||
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.core.GetParameter;
|
||||||
|
import kademlia.exceptions.ContentExistException;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,10 +32,9 @@ class StorageEntryManager
|
|||||||
*
|
*
|
||||||
* @param content The content to store a reference to
|
* @param content The content to store a reference to
|
||||||
*/
|
*/
|
||||||
public void put(KadContent content)
|
public StorageEntry put(KadContent content) throws ContentExistException
|
||||||
{
|
{
|
||||||
StorageEntry entry = new StorageEntry(content);
|
return this.put(new StorageEntry(content));
|
||||||
this.put(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,13 +42,24 @@ class StorageEntryManager
|
|||||||
*
|
*
|
||||||
* @param entry The StorageEntry to store
|
* @param entry The StorageEntry to store
|
||||||
*/
|
*/
|
||||||
public void put(StorageEntry entry)
|
public StorageEntry put(StorageEntry entry) throws ContentExistException
|
||||||
{
|
{
|
||||||
if (!this.entries.containsKey(entry.getKey()))
|
if (!this.entries.containsKey(entry.getKey()))
|
||||||
{
|
{
|
||||||
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>());
|
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>());
|
||||||
}
|
}
|
||||||
this.entries.get(entry.getKey()).add(entry);
|
|
||||||
|
/* If this entry doesn't already exist, then we add it */
|
||||||
|
if (!this.contains(entry))
|
||||||
|
{
|
||||||
|
this.entries.get(entry.getKey()).add(entry);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ContentExistException("Content already exists on this DHT");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,6 +88,27 @@ class StorageEntryManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a content exist in the DHT
|
||||||
|
*/
|
||||||
|
public boolean contains(KadContent content)
|
||||||
|
{
|
||||||
|
return this.contains(new StorageEntry(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a StorageEntry exist on this DHT
|
||||||
|
*/
|
||||||
|
private boolean contains(StorageEntry entry)
|
||||||
|
{
|
||||||
|
if (this.entries.containsKey(entry.getKey()))
|
||||||
|
{
|
||||||
|
return this.entries.get(entry.getKey()).contains(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if our DHT has a Content for the given criteria
|
* Checks if our DHT has a Content for the given criteria
|
||||||
*
|
*
|
||||||
|
21
src/kademlia/exceptions/ContentExistException.java
Normal file
21
src/kademlia/exceptions/ContentExistException.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package kademlia.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception used to indicate that a content already exist on the DHT
|
||||||
|
*
|
||||||
|
* @author Joshua Kissoon
|
||||||
|
* @created 20140322
|
||||||
|
*/
|
||||||
|
public class ContentExistException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
public ContentExistException()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentExistException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
package kademlia.tests;
|
package kademlia.tests;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import kademlia.core.Configuration;
|
||||||
import kademlia.core.Kademlia;
|
import kademlia.core.Kademlia;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
|
||||||
@ -17,31 +21,22 @@ public class AutoRefreshOperationTest
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
/* Setting up 2 Kad networks */
|
/* Setting up 2 Kad networks */
|
||||||
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567463"), 12049);
|
final Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567463"), 12049);
|
||||||
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASF45678947584567464"), 4585);
|
final Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASF45678947584567464"), 4585);
|
||||||
Kademlia kad3 = new Kademlia("Shameer", new NodeId("ASF45678947584567465"), 8104);
|
final Kademlia kad3 = new Kademlia("Shameer", new NodeId("ASF45678947584567465"), 8104);
|
||||||
Kademlia kad4 = new Kademlia("Lokesh", new NodeId("ASF45678947584567466"), 8335);
|
final Kademlia kad4 = new Kademlia("Lokesh", new NodeId("ASF45678947584567466"), 8335);
|
||||||
Kademlia kad5 = new Kademlia("Chandu", new NodeId("ASF45678947584567467"), 13345);
|
final Kademlia kad5 = new Kademlia("Chandu", new NodeId("ASF45678947584567467"), 13345);
|
||||||
|
|
||||||
/* Connecting nodes */
|
/* Connecting nodes */
|
||||||
System.out.println("Connecting Nodes 1 & 2");
|
System.out.println("Connecting Nodes");
|
||||||
kad2.bootstrap(kad1.getNode());
|
kad2.bootstrap(kad1.getNode());
|
||||||
kad3.bootstrap(kad2.getNode());
|
kad3.bootstrap(kad2.getNode());
|
||||||
kad4.bootstrap(kad2.getNode());
|
kad4.bootstrap(kad2.getNode());
|
||||||
kad5.bootstrap(kad4.getNode());
|
kad5.bootstrap(kad4.getNode());
|
||||||
|
|
||||||
System.out.println(kad1);
|
DHTContentImpl c = new DHTContentImpl(kad1.getOwnerId(), "Some Data");
|
||||||
System.out.println(kad2);
|
kad1.putLocally(c);
|
||||||
System.out.println(kad3);
|
System.out.println("\nSTORING CONTENT 1 locally on " + kad1.getOwnerId() + "\n\n\n\n");
|
||||||
System.out.println(kad4);
|
|
||||||
System.out.println(kad5);
|
|
||||||
|
|
||||||
DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
|
|
||||||
kad2.put(c);
|
|
||||||
System.out.println("\n\n\n\nSTORING CONTENT 2\n\n\n\n");
|
|
||||||
DHTContentImpl c2 = new DHTContentImpl(kad2.getOwnerId(), "Some other Data");
|
|
||||||
System.out.println(c2);
|
|
||||||
kad4.put(c2);
|
|
||||||
|
|
||||||
System.out.println(kad1);
|
System.out.println(kad1);
|
||||||
System.out.println(kad2);
|
System.out.println(kad2);
|
||||||
@ -49,14 +44,24 @@ public class AutoRefreshOperationTest
|
|||||||
System.out.println(kad4);
|
System.out.println(kad4);
|
||||||
System.out.println(kad5);
|
System.out.println(kad5);
|
||||||
|
|
||||||
/* Shutting down kad1 and restarting it */
|
/* Print the node states every few minutes */
|
||||||
System.out.println("\n\n\nShutting down Kad instance");
|
Timer timer = new Timer(true);
|
||||||
System.out.println(kad2);
|
timer.schedule(
|
||||||
kad1.shutdown();
|
new TimerTask()
|
||||||
|
{
|
||||||
System.out.println("\n\n\nReloading Kad instance from file");
|
@Override
|
||||||
Kademlia kadR2 = Kademlia.loadFromFile("JoshuaK");
|
public void run()
|
||||||
System.out.println(kadR2);
|
{
|
||||||
|
System.out.println(kad1);
|
||||||
|
System.out.println(kad2);
|
||||||
|
System.out.println(kad3);
|
||||||
|
System.out.println(kad4);
|
||||||
|
System.out.println(kad5);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Delay // Interval
|
||||||
|
Configuration.RESTORE_INTERVAL, Configuration.RESTORE_INTERVAL
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -15,13 +15,13 @@ public class DHTContentImpl implements KadContent
|
|||||||
private final NodeId key;
|
private final NodeId key;
|
||||||
private String data;
|
private String data;
|
||||||
private final String ownerId;
|
private final String ownerId;
|
||||||
private final long createTs;
|
private final long createTs, updateTs;
|
||||||
|
|
||||||
public static final String TYPE = "DHTContentImpl";
|
public static final String TYPE = "DHTContentImpl";
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
this.createTs = System.currentTimeMillis() / 1000L;
|
this.createTs = this.updateTs = System.currentTimeMillis() / 1000L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DHTContentImpl(String ownerId, String data)
|
public DHTContentImpl(String ownerId, String data)
|
||||||
@ -71,6 +71,13 @@ public class DHTContentImpl implements KadContent
|
|||||||
return this.createTs;
|
return this.createTs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastUpdatedTimestamp()
|
||||||
|
{
|
||||||
|
return this.updateTs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "DHTContentImpl[{data=" + this.data + "{ {key:" + this.key + "}]";
|
return "DHTContentImpl[{data=" + this.data + "{ {key:" + this.key + "}]";
|
||||||
|
Loading…
Reference in New Issue
Block a user