Setup Content Updating

- Didn't do this before, but now it's setup: content will be updated on the DHT if a StoreContentMessage is sent with a newer version of the content

GetParameter
- Updated the GetParameter so that it can be constructed from a KadContent object or a StorageEntryMetadata object
- Move it to the DHT package

Others
- Added a few methods to StorageEntryMetadata, StorageEntryManager& DHT to simplify conversions between KadContent, GetParameter & StorageEntryMetadata

Tests
- Written a test to check content updating
This commit is contained in:
Joshua Kissoon 2014-04-05 21:07:57 +05:30
parent cc1d03ba81
commit 2dde2a75e0
12 changed files with 177 additions and 30 deletions

View File

@ -14,7 +14,7 @@ import java.util.NoSuchElementException;
import java.util.Timer;
import java.util.TimerTask;
import kademlia.core.DefaultConfiguration;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.core.KadConfiguration;
import kademlia.core.KadServer;
import kademlia.dht.DHT;

View File

@ -9,7 +9,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
import kademlia.core.GetParameter;
import kademlia.core.KadConfiguration;
import kademlia.exceptions.ContentExistException;
import kademlia.exceptions.ContentNotFoundException;
@ -77,13 +76,43 @@ public class DHT
*
* @param content The DHT content to store
*
* @return boolean true if we stored the content, false if the content already exists and is up to date
*
* @throws java.io.IOException
*/
public void store(StorageEntry content) throws IOException
public boolean store(StorageEntry content) throws IOException
{
/* Keep track of this content in the entries manager */
/* Lets check if we have this content and it's the updated version */
if (this.entriesManager.contains(content.getContentMetadata()))
{
StorageEntryMetadata current = this.entriesManager.get(content.getContentMetadata());
if (current.getLastUpdatedTimestamp() >= content.getContentMetadata().getLastUpdatedTimestamp())
{
/* We have the current content, no need to update it! just leave this method now */
return false;
}
else
{
/* We have this content, but not the latest version, lets delete it so the new version will be added below */
try
{
this.remove(content.getContentMetadata());
}
catch (ContentNotFoundException ex)
{
/* @todo Log an error here */
}
}
}
/**
* If we got here means we don't have this content, or we need to update the content
* If we need to update the content, the code above would've already deleted it, so we just need to re-add it
*/
try
{
System.out.println("Adding new content.");
/* Keep track of this content in the entries manager */
StorageEntryMetadata sEntry = this.entriesManager.put(content.getContentMetadata());
/* Now we store the content locally in a file */
@ -94,16 +123,19 @@ public class DHT
{
this.getSerializer().write(content, dout);
}
return true;
}
catch (ContentExistException e)
{
/* Content already exist on the DHT, no need to do anything here */
/* @todo Content already exist on the DHT, log an error here */
return false;
}
}
public void store(KadContent content) throws IOException
public boolean store(KadContent content) throws IOException
{
this.store(new StorageEntry(content));
return this.store(new StorageEntry(content));
}
/**

View File

@ -1,4 +1,4 @@
package kademlia.core;
package kademlia.dht;
import kademlia.node.NodeId;
@ -35,15 +35,55 @@ public class GetParameter
* Construct a GetParameter to search for data by NodeId, owner, type
*
* @param key
* @param owner
* @param type
* @param owner
*/
public GetParameter(NodeId key, String owner, String type)
public GetParameter(NodeId key, String type, String owner)
{
this(key, owner);
this.type = type;
}
/**
* Construct our get parameter from a Content
*
* @param c
*/
public GetParameter(KadContent c)
{
this.key = c.getKey();
if (c.getType() != null)
{
this.type = c.getType();
}
if (c.getOwnerId() != null)
{
this.ownerId = c.getOwnerId();
}
}
/**
* Construct our get parameter from a StorageEntryMeta data
*
* @param md
*/
public GetParameter(StorageEntryMetadata md)
{
this.key = md.getKey();
if (md.getType() != null)
{
this.type = md.getType();
}
if (md.getOwnerId() != null)
{
this.ownerId = md.getOwnerId();
}
}
public NodeId getKey()
{
return this.key;

View File

@ -5,7 +5,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import kademlia.core.GetParameter;
import kademlia.exceptions.ContentExistException;
import kademlia.exceptions.ContentNotFoundException;
import kademlia.node.NodeId;
@ -76,7 +75,6 @@ class StorageEntryManager
{
if (this.entries.containsKey(param.getKey()))
{
System.out.println("Does contain the key");
/* Content with this key exist, check if any match the rest of the search criteria */
for (StorageEntryMetadata e : this.entries.get(param.getKey()))
{
@ -89,7 +87,6 @@ class StorageEntryManager
}
else
{
System.out.println("Does not contain the key");
System.out.println(this);
}
return false;
@ -100,20 +97,15 @@ class StorageEntryManager
*/
public boolean contains(KadContent content)
{
return this.contains(new StorageEntryMetadata(content));
return this.contains(new GetParameter(content));
}
/**
* Check if a StorageEntry exist on this DHT
*/
private boolean contains(StorageEntryMetadata entry)
public boolean contains(StorageEntryMetadata entry)
{
if (this.entries.containsKey(entry.getKey()))
{
return this.entries.get(entry.getKey()).contains(entry);
}
return false;
return this.contains(new GetParameter(entry));
}
/**
@ -148,6 +140,11 @@ class StorageEntryManager
}
}
public StorageEntryMetadata get(StorageEntryMetadata md)
{
return this.get(new GetParameter(md));
}
/**
* @return A list of all storage entries
*/

View File

@ -1,7 +1,6 @@
package kademlia.dht;
import java.util.Objects;
import kademlia.core.GetParameter;
import kademlia.node.NodeId;
/**
@ -18,7 +17,7 @@ public class StorageEntryMetadata
private final String ownerId;
private final String type;
private final int contentHash;
private final long lastUpdated;
private final long updatedTs;
public StorageEntryMetadata(KadContent content)
{
@ -26,7 +25,7 @@ public class StorageEntryMetadata
this.ownerId = content.getOwnerId();
this.type = content.getType();
this.contentHash = content.hashCode();
this.lastUpdated = content.getLastUpdatedTimestamp();
this.updatedTs = content.getLastUpdatedTimestamp();
}
public NodeId getKey()
@ -49,6 +48,11 @@ public class StorageEntryMetadata
return this.contentHash;
}
public long getLastUpdatedTimestamp()
{
return this.updatedTs;
}
/**
* When a node is looking for content, he sends the search criteria in a GetParameter object
* Here we take this GetParameter object and check if this StorageEntry satisfies the given parameters

View File

@ -3,7 +3,7 @@ package kademlia.message;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.node.Node;
import kademlia.serializer.JsonSerializer;

View File

@ -9,7 +9,7 @@ import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.core.KadConfiguration;
import kademlia.core.KadServer;
import kademlia.dht.StorageEntry;

View File

@ -2,7 +2,7 @@ package kademlia.tests;
import java.io.IOException;
import java.util.List;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.Kademlia;
import kademlia.dht.StorageEntry;
import kademlia.node.NodeId;

View File

@ -0,0 +1,64 @@
package kademlia.tests;
import java.io.IOException;
import java.util.List;
import kademlia.dht.GetParameter;
import kademlia.Kademlia;
import kademlia.dht.StorageEntry;
import kademlia.node.NodeId;
/**
* Testing sending and receiving content between 2 Nodes on a network
*
* @author Joshua Kissoon
* @since 20140224
*/
public class ContentUpdatingTest
{
public static void main(String[] args)
{
try
{
/* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574);
System.out.println("Created Node Kad 1: " + kad1.getNode().getNodeId());
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572);
System.out.println("Created Node Kad 2: " + kad2.getNode().getNodeId());
kad2.bootstrap(kad1.getNode());
/* Lets create the content and share it */
DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
kad2.put(c);
/* Lets retrieve the content */
System.out.println("Retrieving Content");
GetParameter gp = new GetParameter(c.getKey(), DHTContentImpl.TYPE, c.getOwnerId());
System.out.println("Get Parameter: " + gp);
List<StorageEntry> conte = kad2.get(gp, 4);
for (StorageEntry cc : conte)
{
System.out.println("Content Found: " + new DHTContentImpl().fromBytes(cc.getContent()));
System.out.println("Content Metadata: " + cc.getContentMetadata());
}
/* Lets update the content and put it again */
c.setData("Some New Data");
kad2.put(c);
/* Lets retrieve the content */
System.out.println("Retrieving Content Again");
conte = kad2.get(gp, 4);
for (StorageEntry cc : conte)
{
System.out.println("Content Found: " + new DHTContentImpl().fromBytes(cc.getContent()));
System.out.println("Content Metadata: " + cc.getContentMetadata());
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

View File

@ -18,7 +18,8 @@ public class DHTContentImpl implements KadContent
private NodeId key;
private String data;
private String ownerId;
private long createTs, updateTs;
private final long createTs;
private long updateTs;
{
@ -46,6 +47,7 @@ public class DHTContentImpl implements KadContent
public void setData(String newData)
{
this.data = newData;
this.setUpdated();
}
@Override
@ -66,6 +68,14 @@ public class DHTContentImpl implements KadContent
return this.ownerId;
}
/**
* Set the content as updated
*/
public void setUpdated()
{
this.updateTs = System.currentTimeMillis() / 1000L;
}
@Override
public long getCreatedTimestamp()
{

View File

@ -2,7 +2,7 @@ package kademlia.tests;
import java.io.IOException;
import java.util.List;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.Kademlia;
import kademlia.dht.StorageEntry;
import kademlia.node.NodeId;

View File

@ -2,7 +2,7 @@ package kademlia.tests;
import java.util.List;
import kademlia.Kademlia;
import kademlia.core.GetParameter;
import kademlia.dht.GetParameter;
import kademlia.dht.StorageEntry;
import kademlia.node.NodeId;