package socialkademlia.operation;
import java.io.IOException;
import java.util.List;
import kademlia.KadConfiguration;
import kademlia.KadServer;
import kademlia.exceptions.ContentNotFoundException;
import kademlia.message.Message;
import socialkademlia.message.StoreContentMessage;
import kademlia.node.Node;
import kademlia.operation.Operation;
import socialkademlia.SocialKademliaNode;
import socialkademlia.dht.SocialKademliaDHT;
import socialkademlia.dht.SocialKademliaStorageEntryMetadata;
/**
* Refresh/Restore the data on this node by sending the data to the K-Closest nodes to the data
*
* @author Joshua Kissoon
* @since 20140306
*/
public class ContentRefreshOperation implements Operation
{
private final KadServer server;
private final SocialKademliaNode localNode;
private final SocialKademliaDHT dht;
private final KadConfiguration config;
public ContentRefreshOperation(KadServer server, SocialKademliaNode localNode, SocialKademliaDHT dht, KadConfiguration config)
{
this.server = server;
this.localNode = localNode;
this.dht = dht;
this.config = config;
}
/**
* For each content stored on this JSocialKademliaDHT, distribute it to the K closest nodes
Also delete the content if this node is no longer one of the K closest nodes
We assume that our RoutingTable is updated, and we can get the K closest nodes from that table
*
* @throws java.io.IOException
*/
@Override
public void execute() throws IOException
{
/* Get a list of all storage entries for content */
List<SocialKademliaStorageEntryMetadata> entries = this.dht.getStorageEntries();
/* If a content was last republished before this time, then we need to republish it */
final long minRepublishTime = (System.currentTimeMillis() / 1000L) - this.config.restoreInterval();
/* For each storage entry, distribute it */
for (SocialKademliaStorageEntryMetadata e : entries)
{
/* Check last update time of this entry and only distribute it if it has been last updated > 1 hour ago */
if (e.lastRepublished() > minRepublishTime)
{
continue;
}
/* If this is a cached content and we're not one of the k-closest nodes nor the owner; this node is not responsible for republishing it */
if (e.isCached() && !e.isKNode() && !e.getOwnerId().equals(this.localNode.getOwnerId()))
{
continue;
}
/* Set that this content is now republished */
e.updateLastRepublished();
/* Get the K closest nodes to this entries */
List<Node> closestNodes = this.localNode.getRoutingTable().findClosest(e.getKey(), this.config.k());
/* Create the message */
Message msg = new StoreContentMessage(this.localNode.getNode(), dht.get(e));
/*Store the message on all of the K-Nodes*/
for (Node n : closestNodes)
{
/*We don't need to again store the content locally, it's already here*/
if (!n.equals(this.localNode.getNode()))
{
/* Send a contentstore operation to the K-Closest nodes */
this.server.sendMessage(n, msg, null);
}
}
/* Delete any content on this node that this node is not one of the K-Closest nodes to */
try
{
if (!closestNodes.contains(this.localNode.getNode()))
{
this.dht.remove(e);
}
}
catch (ContentNotFoundException cnfe)
{
/* It would be weird if the content is not found here */
System.err.println("ContentRefreshOperation: Removing content from local node, content not found... Message: " + cnfe.getMessage());
}
}
}
}