Problem with serializing the DHT also, had to create a DHT specific Serializer class

This commit is contained in:
Joshua Kissoon 2014-03-10 14:37:08 +05:30
parent e2ca9326c9
commit 22fee9116a
9 changed files with 223 additions and 32 deletions

View File

@ -25,6 +25,7 @@ import kademlia.operation.Operation;
import kademlia.operation.KadRefreshOperation; import kademlia.operation.KadRefreshOperation;
import kademlia.operation.StoreOperation; import kademlia.operation.StoreOperation;
import kademlia.routing.RoutingTable; import kademlia.routing.RoutingTable;
import kademlia.serializer.JsonDHTSerializer;
import kademlia.serializer.JsonRoutingTableSerializer; import kademlia.serializer.JsonRoutingTableSerializer;
import kademlia.serializer.JsonSerializer; import kademlia.serializer.JsonSerializer;
@ -42,6 +43,7 @@ import kademlia.serializer.JsonSerializer;
* @todo If we're trying to send a message to this node, just cancel the sending process and handle the message right here * @todo If we're trying to send a message to this node, just cancel the sending process and handle the message right here
* @todo Keep this node in it's own routing table - it helps for ContentRefresh operation - easy to check whether this node is one of the k-nodes for a content * @todo Keep this node in it's own routing table - it helps for ContentRefresh operation - easy to check whether this node is one of the k-nodes for a content
* @todo Move DHT.getContentStorageFolderName to the Configuration class * @todo Move DHT.getContentStorageFolderName to the Configuration class
* @todo Implement Kademlia.ping() operation.
* *
*/ */
public class Kademlia public class Kademlia
@ -152,7 +154,7 @@ public class Kademlia
* @section Read the DHT * @section Read the DHT
*/ */
din = new DataInputStream(new FileInputStream(getStateStorageFolderName(ownerId) + File.separator + "dht.kns")); din = new DataInputStream(new FileInputStream(getStateStorageFolderName(ownerId) + File.separator + "dht.kns"));
DHT idht = new JsonSerializer<DHT>().read(din); DHT idht = new JsonDHTSerializer().read(din);
System.out.println("Finished reading data."); System.out.println("Finished reading data.");
return new Kademlia(ownerId, inode, ikad.getPort(), idht); return new Kademlia(ownerId, inode, ikad.getPort(), idht);
} }
@ -319,7 +321,7 @@ public class Kademlia
* @section Save the DHT * @section Save the DHT
*/ */
dout = new DataOutputStream(new FileOutputStream(getStateStorageFolderName(this.ownerId) + File.separator + "dht.kns")); dout = new DataOutputStream(new FileOutputStream(getStateStorageFolderName(this.ownerId) + File.separator + "dht.kns"));
new JsonSerializer<DHT>().write(this.dht, dout); new JsonDHTSerializer().write(this.dht, dout);
System.out.println("FInished saving state"); System.out.println("FInished saving state");
@ -381,6 +383,11 @@ public class Kademlia
sb.append(this.localNode.getRoutingTable()); sb.append(this.localNode.getRoutingTable());
sb.append("\n"); sb.append("\n");
sb.append("\n");
sb.append("DHT: ");
sb.append(this.dht);
sb.append("\n");
sb.append("\n\n\n"); sb.append("\n\n\n");
return sb.toString(); return sb.toString();

View File

@ -23,15 +23,27 @@ import kademlia.serializer.JsonSerializer;
public class DHT public class DHT
{ {
private final StorageEntryManager entriesManager; private transient StorageEntryManager entriesManager;
private transient final JsonSerializer<KadContent> contentSerializer; private transient final JsonSerializer<KadContent> contentSerializer;
{ {
entriesManager = new StorageEntryManager();
contentSerializer = new JsonSerializer<>(); contentSerializer = new JsonSerializer<>();
} }
public DHT()
{
this.initialize();
}
/**
* Initialize this DHT to it's default state
*/
public final void initialize()
{
entriesManager = new StorageEntryManager();
}
/** /**
* Handle storing content locally * Handle storing content locally
* *
@ -178,4 +190,24 @@ public class DHT
{ {
return entriesManager.getAllEntries(); return entriesManager.getAllEntries();
} }
/**
* Used to add a list of storage entries for existing content to the DHT.
* Mainly used when retrieving StorageEntries from a saved state file.
*
* @param ientries The entries to add
*/
public void putStorageEntries(List<StorageEntry> ientries)
{
for (StorageEntry e : ientries)
{
this.entriesManager.put(e);
}
}
@Override
public String toString()
{
return this.entriesManager.toString();
}
} }

View File

@ -70,12 +70,7 @@ public class StorageEntry
} }
/* Check that key matches */ /* Check that key matches */
if ((params.getKey() != null) && (!params.getKey().equals(this.key))) return ((params.getKey() != null) && (!params.getKey().equals(this.key)));
{
return false;
}
return true;
} }
@Override @Override
@ -98,4 +93,23 @@ public class StorageEntry
hash = 23 * hash + Objects.hashCode(this.type); hash = 23 * hash + Objects.hashCode(this.type);
return hash; return hash;
} }
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("[StorageEntry: ");
sb.append("{Key: ");
sb.append(this.key);
sb.append("} ");
sb.append("{Owner: ");
sb.append(this.ownerId);
sb.append("} ");
sb.append("{Type: ");
sb.append(this.type);
sb.append("} ");
sb.append("]");
return sb.toString();
}
} }

View File

@ -16,7 +16,7 @@ import kademlia.node.NodeId;
* @author Joshua Kissoon * @author Joshua Kissoon
* @since 20140226 * @since 20140226
*/ */
public class StorageEntryManager class StorageEntryManager
{ {
private final Map<NodeId, List<StorageEntry>> entries; private final Map<NodeId, List<StorageEntry>> entries;
@ -34,6 +34,16 @@ public class StorageEntryManager
public void put(KadContent content) public void put(KadContent content)
{ {
StorageEntry entry = new StorageEntry(content); StorageEntry entry = new StorageEntry(content);
this.put(entry);
}
/**
* Add a new entry to our storage
*
* @param entry The StorageEntry to store
*/
public void put(StorageEntry entry)
{
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>());
@ -116,4 +126,26 @@ public class StorageEntryManager
return entriesRet; return entriesRet;
} }
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("Stored Content: \n");
for (List<StorageEntry> es : this.entries.values())
{
if (entries.size() < 1)
{
continue;
}
for (StorageEntry e : es)
{
sb.append(e);
sb.append("\n");
}
}
sb.append("\n");
return sb.toString();
}
} }

View File

@ -30,12 +30,24 @@ public class RoutingTable
this.localNode = localNode; this.localNode = localNode;
/* Initialize all of the buckets to a specific depth */ /* Initialize all of the buckets to a specific depth */
this.initializeBuckets(); this.initialize();
/* @todo Insert the local node */ /* @todo Insert the local node */
//this.insert(localNode); //this.insert(localNode);
} }
/**
* Initialize the RoutingTable to it's default state
*/
public final void initialize()
{
this.buckets = new KadBucket[NodeId.ID_LENGTH];
for (int i = 0; i < NodeId.ID_LENGTH; i++)
{
buckets[i] = new KadBucket(i);
}
}
/** /**
* Adds a new node to the routing table * Adds a new node to the routing table
* *
@ -180,18 +192,6 @@ public class RoutingTable
this.buckets = buckets; this.buckets = buckets;
} }
/**
* Initialize the kadBuckets to be empty
*/
public final void initializeBuckets()
{
this.buckets = new KadBucket[NodeId.ID_LENGTH];
for (int i = 0; i < NodeId.ID_LENGTH; i++)
{
buckets[i] = new KadBucket(i);
}
}
@Override @Override
public final String toString() public final String toString()
{ {

View File

@ -0,0 +1,94 @@
package kademlia.serializer;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.util.List;
import kademlia.dht.DHT;
import kademlia.dht.StorageEntry;
/**
* A KadSerializer that serializes DHT to JSON format
* The generic serializer is not working for DHT
*
* Why a DHT specific serializer?
* The DHT structure:
* - DHT
* -- StorageEntriesManager
* --- Map<NodeId, List<StorageEntry>>
* ---- NodeId:KeyBytes
* ---- List<StorageEntry>
* ----- StorageEntry: Key, OwnerId, Type, Hash
*
* The above structure seems to be causing some problem for Gson, especially at the Map part.
*
* Solution
* - Make the StorageEntriesManager transient
* - Simply store all StorageEntry in the serialized object
* - When reloading, re-add all StorageEntry to the DHT
*
* @author Joshua Kissoon
*
* @since 20140310
*/
public class JsonDHTSerializer implements KadSerializer<DHT>
{
private final Gson gson;
private final Type storageEntriesCollectionType;
{
gson = new Gson();
storageEntriesCollectionType = new TypeToken<List<StorageEntry>>()
{
}.getType();
}
@Override
public void write(DHT data, DataOutputStream out) throws IOException
{
try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out)))
{
writer.beginArray();
/* Write the basic DHT */
gson.toJson(data, DHT.class, writer);
/* Now Store the Entries */
gson.toJson(data.getStorageEntries(), this.storageEntriesCollectionType, writer);
writer.endArray();
}
}
@Override
public DHT read(DataInputStream in) throws IOException, ClassNotFoundException
{
try (DataInputStream din = new DataInputStream(in);
JsonReader reader = new JsonReader(new InputStreamReader(in)))
{
reader.beginArray();
/* Read the basic DHT */
DHT dht = gson.fromJson(reader, DHT.class);
dht.initialize();
/* Now get the entries and add them back to the DHT */
List<StorageEntry> entries = gson.fromJson(reader, this.storageEntriesCollectionType);
dht.putStorageEntries(entries);
reader.endArray();
return dht;
}
}
}

View File

@ -36,7 +36,7 @@ import kademlia.node.Node;
* *
* @author Joshua Kissoon * @author Joshua Kissoon
* *
* @since 20140225 * @since 20140310
*/ */
public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable> public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
{ {
@ -85,7 +85,7 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
{ {
}.getType(); }.getType();
List<Node> nodes = gson.fromJson(reader, collectionType); List<Node> nodes = gson.fromJson(reader, collectionType);
tbl.initializeBuckets(); tbl.initialize();
for (Node n : nodes) for (Node n : nodes)
{ {

View File

@ -73,6 +73,6 @@ public class DHTContentImpl implements KadContent
public String toString() public String toString()
{ {
return "DHTContentImpl[data=" + this.data + "]"; return "DHTContentImpl[{data=" + this.data + "{ {key:"+this.key + "}]";
} }
} }

View File

@ -12,21 +12,28 @@ import kademlia.node.NodeId;
public class SaveStateTest public class SaveStateTest
{ {
public static void main(String[] args) public SaveStateTest()
{ {
try try
{ {
/* Setting up 2 Kad networks */ /* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574); Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7529);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572); Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7532);
/* Connecting 2 to 1 */ /* Connecting 2 to 1 */
System.out.println("Connecting Kad 1 and Kad 2"); System.out.println("Connecting Kad 1 and Kad 2");
kad1.connect(kad2.getNode()); kad1.connect(kad2.getNode());
synchronized (this)
{
DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
System.out.println(c);
kad2.put(c);
}
System.out.println(kad1); System.out.println(kad1);
System.out.println(kad2); System.out.println(kad2);
/* Shutting down kad1 and restarting it */ /* Shutting down kad1 and restarting it */
System.out.println("\n\n\nShutting down Kad instance"); System.out.println("\n\n\nShutting down Kad instance");
kad1.shutdown(); kad1.shutdown();
@ -40,4 +47,9 @@ public class SaveStateTest
e.printStackTrace();; e.printStackTrace();;
} }
} }
public static void main(String[] args)
{
new SaveStateTest();
}
} }