Setup storing of System state on shutdown

This commit is contained in:
Joshua Kissoon 2014-03-09 20:12:11 +05:30
parent 630f8c2f28
commit eb7d7b53a4
6 changed files with 118 additions and 13 deletions

View File

@ -52,5 +52,10 @@ public class Configuration
/** /**
* Local Storage location - Relative to the user's home folder (Cross-Platform) * Local Storage location - Relative to the user's home folder (Cross-Platform)
*/ */
public static String localFolder = "kademlia"; public static String LOCAL_FOLDER = "kademlia";
/**
* Should we save the node state when the node is shut down and reload it when the node is re-loaded
*/
public static boolean SAVE_STATE_ON_SHUTDOWN = true;
} }

View File

@ -250,14 +250,23 @@ public class KadServer
*/ */
private synchronized void unregister(int comm) private synchronized void unregister(int comm)
{ {
Integer key = comm; receivers.remove(comm);
receivers.remove(key); this.tasks.remove(comm);
this.tasks.remove(key); }
/**
* Stops listening and shuts down the server
*/
public void shutdown()
{
this.isRunning = false;
this.socket.close();
timer.cancel();
} }
/** /**
* Task that gets called by a separate thread if a timeout for a receiver occurs. * Task that gets called by a separate thread if a timeout for a receiver occurs.
* When a reply arrives this task must be cancelled using the <code>cancel()</code> * When a reply arrives this task must be canceled using the <code>cancel()</code>
* method inherited from <code>TimerTask</code>. In this case the caller is * method inherited from <code>TimerTask</code>. In this case the caller is
* responsible for removing the task from the <code>tasks</code> map. * responsible for removing the task from the <code>tasks</code> map.
* */ * */

View File

@ -1,5 +1,9 @@
package kademlia.core; package kademlia.core;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,6 +22,7 @@ import kademlia.operation.ContentLookupOperation;
import kademlia.operation.Operation; import kademlia.operation.Operation;
import kademlia.operation.KadRefreshOperation; import kademlia.operation.KadRefreshOperation;
import kademlia.operation.StoreOperation; import kademlia.operation.StoreOperation;
import kademlia.serializer.JsonSerializer;
/** /**
* The main Kademlia network management class * The main Kademlia network management class
@ -32,6 +37,7 @@ import kademlia.operation.StoreOperation;
* @todo Instead of using a StoreContentMessage to send a store RPC and a ContentMessage to receive a FIND rpc, make them 1 message with different operation type * @todo Instead of using a StoreContentMessage to send a store RPC and a ContentMessage to receive a FIND rpc, make them 1 message with different operation type
* @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
* *
*/ */
public class Kademlia public class Kademlia
@ -45,6 +51,7 @@ public class Kademlia
private final KadServer server; private final KadServer server;
private final DHT dht; private final DHT dht;
private final Timer timer; private final Timer timer;
private final int udpPort;
/* Factories */ /* Factories */
private final MessageFactory messageFactory; private final MessageFactory messageFactory;
@ -56,17 +63,18 @@ public class Kademlia
* address of a bootstrap node in the network. * address of a bootstrap node in the network.
* *
* @param ownerId The Name of this node used for storage * @param ownerId The Name of this node used for storage
* @param defaultId Default id for the node * @param localNode The Local Node for this Kad instance
* @param udpPort The UDP port to use for routing messages * @param udpPort The UDP port to use for routing messages
* *
* @throws IOException If an error occurred while reading id or local map * @throws IOException If an error occurred while reading id or local map
* from disk <i>or</i> a network error occurred while * from disk <i>or</i> a network error occurred while
* attempting to connect to the network * attempting to connect to the network
* */ * */
public Kademlia(String ownerId, NodeId defaultId, int udpPort) throws IOException public Kademlia(String ownerId, Node localNode, int udpPort) throws IOException
{ {
this.ownerId = ownerId; this.ownerId = ownerId;
this.localNode = new Node(defaultId, InetAddress.getLocalHost(), udpPort); this.udpPort = udpPort;
this.localNode = localNode;
this.dht = new DHT(); this.dht = new DHT();
this.messageFactory = new MessageFactory(localNode, this.dht); this.messageFactory = new MessageFactory(localNode, this.dht);
this.server = new KadServer(udpPort, this.messageFactory, this.localNode); this.server = new KadServer(udpPort, this.messageFactory, this.localNode);
@ -95,6 +103,21 @@ public class Kademlia
); );
} }
public Kademlia(String ownerId, NodeId defaultId, int udpPort) throws IOException
{
this(ownerId, new Node(defaultId, InetAddress.getLocalHost(), udpPort), udpPort);
}
/**
* @return A Kademlia instance loaded from a stored state in a file
*
* @todo Boot up this Kademlia instance from a saved file state
*/
// public Kademlia loadFromFile(String ownerId)
// {
//
// }
/** /**
* @return Node The local node for this system * @return Node The local node for this system
*/ */
@ -196,4 +219,72 @@ public class Kademlia
{ {
return this.ownerId; return this.ownerId;
} }
/**
* Here we handle properly shutting down the Kademlia instance
*
* @throws java.io.FileNotFoundException
*/
public void shutdown() throws FileNotFoundException, IOException
{
/* Save this Kademlia instance's state if required */
if (Configuration.SAVE_STATE_ON_SHUTDOWN)
{
/* Save the system state */
this.saveKadState();
}
/* Shut down the server */
this.server.shutdown();
/* Now we store the content locally in a file */
}
/**
* Saves the node state to a text file
*
* @throws java.io.FileNotFoundException
*/
private void saveKadState() throws FileNotFoundException, IOException
{
/* Setup the file in which we store the state */
DataOutputStream dout = new DataOutputStream(new FileOutputStream(this.getStateStorageFolderName() + File.separator + this.ownerId + ".kns"));
/* Save the UDP Port that this app is running on */
new JsonSerializer<Integer>().write(this.udpPort, dout);
/* Save the node state */
new JsonSerializer<Node>().write(this.localNode, dout);
/* Save the DHT */
new JsonSerializer<DHT>().write(this.dht, dout);
}
/**
* Get the name of the folder for which a content should be stored
*
* @return String The name of the folder to store node states
*/
private String getStateStorageFolderName()
{
String storagePath = System.getProperty("user.home") + File.separator + Configuration.LOCAL_FOLDER;
File mainStorageFolder = new File(storagePath);
/* Create the main storage folder if it doesn't exist */
if (!mainStorageFolder.isDirectory())
{
mainStorageFolder.mkdir();
}
File contentStorageFolder = new File(mainStorageFolder + File.separator + "nodes");
/* Create the content folder if it doesn't exist */
if (!contentStorageFolder.isDirectory())
{
contentStorageFolder.mkdir();
}
return mainStorageFolder + File.separator + "nodes";
}
} }

View File

@ -150,7 +150,7 @@ public class DHT
* *
* The name of the file containing the content is the hash of this content * The name of the file containing the content is the hash of this content
*/ */
String storagePath = System.getProperty("user.home") + File.separator + Configuration.localFolder; String storagePath = System.getProperty("user.home") + File.separator + Configuration.LOCAL_FOLDER;
File mainStorageFolder = new File(storagePath); File mainStorageFolder = new File(storagePath);
/* Create the main storage folder if it doesn't exist */ /* Create the main storage folder if it doesn't exist */

View File

@ -10,7 +10,7 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
/** /**
* A KadContentSerializer that serializes content to JSON format * A KadSerializer that serializes content to JSON format
* *
* @param <T> The type of content to serialize * @param <T> The type of content to serialize
* *
@ -18,7 +18,7 @@ import java.io.OutputStreamWriter;
* *
* @since 20140225 * @since 20140225
*/ */
public class JsonSerializer<T> implements KadContentSerializer<T> public class JsonSerializer<T> implements KadSerializer<T>
{ {
private final Gson gson; private final Gson gson;

View File

@ -14,7 +14,7 @@ import java.io.IOException;
* *
* @since 20140225 * @since 20140225
*/ */
public interface KadContentSerializer<T> public interface KadSerializer<T>
{ {
/** /**