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.StoreOperation;
import kademlia.routing.RoutingTable;
import kademlia.serializer.JsonDHTSerializer;
import kademlia.serializer.JsonRoutingTableSerializer;
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 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 Implement Kademlia.ping() operation.
*
*/
public class Kademlia
@ -152,7 +154,7 @@ public class Kademlia
* @section Read the DHT
*/
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.");
return new Kademlia(ownerId, inode, ikad.getPort(), idht);
}
@ -319,7 +321,7 @@ public class Kademlia
* @section Save the DHT
*/
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");
@ -381,6 +383,11 @@ public class Kademlia
sb.append(this.localNode.getRoutingTable());
sb.append("\n");
sb.append("\n");
sb.append("DHT: ");
sb.append(this.dht);
sb.append("\n");
sb.append("\n\n\n");
return sb.toString();

View File

@ -23,15 +23,27 @@ import kademlia.serializer.JsonSerializer;
public class DHT
{
private final StorageEntryManager entriesManager;
private transient StorageEntryManager entriesManager;
private transient final JsonSerializer<KadContent> contentSerializer;
{
entriesManager = new StorageEntryManager();
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
*
@ -178,4 +190,24 @@ public class DHT
{
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 */
if ((params.getKey() != null) && (!params.getKey().equals(this.key)))
{
return false;
}
return true;
return ((params.getKey() != null) && (!params.getKey().equals(this.key)));
}
@Override
@ -98,4 +93,23 @@ public class StorageEntry
hash = 23 * hash + Objects.hashCode(this.type);
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
* @since 20140226
*/
public class StorageEntryManager
class StorageEntryManager
{
private final Map<NodeId, List<StorageEntry>> entries;
@ -34,6 +34,16 @@ public class StorageEntryManager
public void put(KadContent 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()))
{
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>());
@ -116,4 +126,26 @@ public class StorageEntryManager
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;
/* Initialize all of the buckets to a specific depth */
this.initializeBuckets();
this.initialize();
/* @todo Insert the local node */
//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
*
@ -180,18 +192,6 @@ public class RoutingTable
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
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
*
* @since 20140225
* @since 20140310
*/
public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
{
@ -85,7 +85,7 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
{
}.getType();
List<Node> nodes = gson.fromJson(reader, collectionType);
tbl.initializeBuckets();
tbl.initialize();
for (Node n : nodes)
{

View File

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

View File

@ -12,18 +12,25 @@ import kademlia.node.NodeId;
public class SaveStateTest
{
public static void main(String[] args)
public SaveStateTest()
{
try
{
/* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572);
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7529);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7532);
/* Connecting 2 to 1 */
System.out.println("Connecting Kad 1 and Kad 2");
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(kad2);
@ -40,4 +47,9 @@ public class SaveStateTest
e.printStackTrace();;
}
}
public static void main(String[] args)
{
new SaveStateTest();
}
}