mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-11-22 10:12:19 +00:00
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:
parent
cc1d03ba81
commit
2dde2a75e0
@ -14,7 +14,7 @@ import java.util.NoSuchElementException;
|
|||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import kademlia.core.DefaultConfiguration;
|
import kademlia.core.DefaultConfiguration;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.core.KadConfiguration;
|
import kademlia.core.KadConfiguration;
|
||||||
import kademlia.core.KadServer;
|
import kademlia.core.KadServer;
|
||||||
import kademlia.dht.DHT;
|
import kademlia.dht.DHT;
|
||||||
|
@ -9,7 +9,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import kademlia.core.GetParameter;
|
|
||||||
import kademlia.core.KadConfiguration;
|
import kademlia.core.KadConfiguration;
|
||||||
import kademlia.exceptions.ContentExistException;
|
import kademlia.exceptions.ContentExistException;
|
||||||
import kademlia.exceptions.ContentNotFoundException;
|
import kademlia.exceptions.ContentNotFoundException;
|
||||||
@ -77,13 +76,43 @@ public class DHT
|
|||||||
*
|
*
|
||||||
* @param content The DHT content to store
|
* @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
|
* @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
|
try
|
||||||
{
|
{
|
||||||
|
System.out.println("Adding new content.");
|
||||||
|
/* Keep track of this content in the entries manager */
|
||||||
StorageEntryMetadata sEntry = this.entriesManager.put(content.getContentMetadata());
|
StorageEntryMetadata sEntry = this.entriesManager.put(content.getContentMetadata());
|
||||||
|
|
||||||
/* Now we store the content locally in a file */
|
/* Now we store the content locally in a file */
|
||||||
@ -94,16 +123,19 @@ public class DHT
|
|||||||
{
|
{
|
||||||
this.getSerializer().write(content, dout);
|
this.getSerializer().write(content, dout);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (ContentExistException e)
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package kademlia.core;
|
package kademlia.dht;
|
||||||
|
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
|
||||||
@ -35,15 +35,55 @@ public class GetParameter
|
|||||||
* Construct a GetParameter to search for data by NodeId, owner, type
|
* Construct a GetParameter to search for data by NodeId, owner, type
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param owner
|
|
||||||
* @param type
|
* @param type
|
||||||
|
* @param owner
|
||||||
*/
|
*/
|
||||||
public GetParameter(NodeId key, String owner, String type)
|
public GetParameter(NodeId key, String type, String owner)
|
||||||
{
|
{
|
||||||
this(key, owner);
|
this(key, owner);
|
||||||
this.type = type;
|
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()
|
public NodeId getKey()
|
||||||
{
|
{
|
||||||
return this.key;
|
return this.key;
|
@ -5,7 +5,6 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
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.exceptions.ContentExistException;
|
import kademlia.exceptions.ContentExistException;
|
||||||
import kademlia.exceptions.ContentNotFoundException;
|
import kademlia.exceptions.ContentNotFoundException;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
@ -76,7 +75,6 @@ class StorageEntryManager
|
|||||||
{
|
{
|
||||||
if (this.entries.containsKey(param.getKey()))
|
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 */
|
/* Content with this key exist, check if any match the rest of the search criteria */
|
||||||
for (StorageEntryMetadata e : this.entries.get(param.getKey()))
|
for (StorageEntryMetadata e : this.entries.get(param.getKey()))
|
||||||
{
|
{
|
||||||
@ -89,7 +87,6 @@ class StorageEntryManager
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
System.out.println("Does not contain the key");
|
|
||||||
System.out.println(this);
|
System.out.println(this);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -100,20 +97,15 @@ class StorageEntryManager
|
|||||||
*/
|
*/
|
||||||
public boolean contains(KadContent content)
|
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
|
* 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.contains(new GetParameter(entry));
|
||||||
{
|
|
||||||
return this.entries.get(entry.getKey()).contains(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,6 +140,11 @@ class StorageEntryManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StorageEntryMetadata get(StorageEntryMetadata md)
|
||||||
|
{
|
||||||
|
return this.get(new GetParameter(md));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A list of all storage entries
|
* @return A list of all storage entries
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package kademlia.dht;
|
package kademlia.dht;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import kademlia.core.GetParameter;
|
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,7 +17,7 @@ public class StorageEntryMetadata
|
|||||||
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;
|
private final long updatedTs;
|
||||||
|
|
||||||
public StorageEntryMetadata(KadContent content)
|
public StorageEntryMetadata(KadContent content)
|
||||||
{
|
{
|
||||||
@ -26,7 +25,7 @@ public class StorageEntryMetadata
|
|||||||
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();
|
this.updatedTs = content.getLastUpdatedTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeId getKey()
|
public NodeId getKey()
|
||||||
@ -49,6 +48,11 @@ public class StorageEntryMetadata
|
|||||||
return this.contentHash;
|
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
|
* 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
|
* Here we take this GetParameter object and check if this StorageEntry satisfies the given parameters
|
||||||
|
@ -3,7 +3,7 @@ package kademlia.message;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.node.Node;
|
import kademlia.node.Node;
|
||||||
import kademlia.serializer.JsonSerializer;
|
import kademlia.serializer.JsonSerializer;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.core.KadConfiguration;
|
import kademlia.core.KadConfiguration;
|
||||||
import kademlia.core.KadServer;
|
import kademlia.core.KadServer;
|
||||||
import kademlia.dht.StorageEntry;
|
import kademlia.dht.StorageEntry;
|
||||||
|
@ -2,7 +2,7 @@ package kademlia.tests;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.Kademlia;
|
import kademlia.Kademlia;
|
||||||
import kademlia.dht.StorageEntry;
|
import kademlia.dht.StorageEntry;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
64
src/kademlia/tests/ContentUpdatingTest.java
Normal file
64
src/kademlia/tests/ContentUpdatingTest.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,8 @@ public class DHTContentImpl implements KadContent
|
|||||||
private NodeId key;
|
private NodeId key;
|
||||||
private String data;
|
private String data;
|
||||||
private String ownerId;
|
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)
|
public void setData(String newData)
|
||||||
{
|
{
|
||||||
this.data = newData;
|
this.data = newData;
|
||||||
|
this.setUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,6 +68,14 @@ public class DHTContentImpl implements KadContent
|
|||||||
return this.ownerId;
|
return this.ownerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the content as updated
|
||||||
|
*/
|
||||||
|
public void setUpdated()
|
||||||
|
{
|
||||||
|
this.updateTs = System.currentTimeMillis() / 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getCreatedTimestamp()
|
public long getCreatedTimestamp()
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@ package kademlia.tests;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.Kademlia;
|
import kademlia.Kademlia;
|
||||||
import kademlia.dht.StorageEntry;
|
import kademlia.dht.StorageEntry;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
@ -2,7 +2,7 @@ package kademlia.tests;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import kademlia.Kademlia;
|
import kademlia.Kademlia;
|
||||||
import kademlia.core.GetParameter;
|
import kademlia.dht.GetParameter;
|
||||||
import kademlia.dht.StorageEntry;
|
import kademlia.dht.StorageEntry;
|
||||||
import kademlia.node.NodeId;
|
import kademlia.node.NodeId;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user