Fixed the bug that was causing replication of content files and StorageEntries. RefreshOperation working well!!

This commit is contained in:
Joshua Kissoon 2014-03-22 15:27:22 +05:30
parent b93133337c
commit d9fdcc57fd
8 changed files with 134 additions and 44 deletions

View File

@ -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.

View File

@ -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 */
}
} }
} }

View File

@ -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
*/ */

View File

@ -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()
@ -109,7 +111,7 @@ public class StorageEntry
sb.append(this.type); sb.append(this.type);
sb.append("} "); sb.append("} ");
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();
} }
} }

View File

@ -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
* *

View 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);
}
}

View File

@ -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)

View File

@ -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 + "}]";