package com.yahoo.dtf.components;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import com.yahoo.dtf.DTFConstants;
import com.yahoo.dtf.DTFNode;
import com.yahoo.dtf.actions.Action;
import com.yahoo.dtf.actions.file.PullFile;
import com.yahoo.dtf.actions.protocol.CleanUpHook;
import com.yahoo.dtf.actions.storage.Createstorage;
import com.yahoo.dtf.comm.rpc.Node;
import com.yahoo.dtf.exception.DTFException;
import com.yahoo.dtf.state.ActionState;
import com.yahoo.dtf.storage.StorageFactory;
import com.yahoo.dtf.storage.StorageIntf;
public class StorageState implements ComponentHook,
ComponentReturnHook,
ComponentUnlockHook,
CleanUpHook {
private static String SSFILES = "dtf.storage.storages.ctx";
private static String SSSTORAGE = "dtf.storage.files.ctx";
private static Object getGlobalContext(String id ) {
if ( DTFNode.getType().equals(DTFConstants.DTFX_ID) ) {
return Action.getGlobalContext(id);
}
ActionState as = ActionState.getInstance();
return as.getState(Node.BASE_CONFIG).getGlobalContext(id);
}
private static void registerGlobalContext(String id, Object obj ) {
if ( DTFNode.getType().equals(DTFConstants.DTFX_ID) ) {
Action.registerGlobalContext(id, obj);
}
ActionState as = ActionState.getInstance();
as.getState(Node.BASE_CONFIG).registerGlobalContext(id, obj);
}
private static HashMap<String, HashMap<String,Long>> getSent(String id) {
HashMap<String,HashMap<String,HashMap<String,Long>>> sent =
(HashMap<String,HashMap<String,HashMap<String,Long>>>)
getGlobalContext(SSFILES);
if ( sent == null ) {
sent = new HashMap<String,HashMap<String,HashMap<String,Long>>>();
registerGlobalContext(SSFILES, sent);
}
HashMap<String, HashMap<String,Long>> sentfiles = sent.get(id);
if ( sentfiles == null ) {
sentfiles = new HashMap<String, HashMap<String,Long>>();
sent.put(id, sentfiles);
}
return sentfiles;
}
private static ArrayList<String> getStorages(String id) {
HashMap<String, ArrayList<String>> cstorage =
(HashMap<String, ArrayList<String>>) getGlobalContext(SSSTORAGE);
if ( cstorage == null ) {
cstorage = new HashMap<String, ArrayList<String>>();
registerGlobalContext(SSSTORAGE, cstorage);
}
ArrayList<String> sentstorages = cstorage.get(id);
if ( sentstorages == null ) {
sentstorages = new ArrayList<String>();
cstorage.put(id, sentstorages);
}
return sentstorages;
}
public synchronized ArrayList<Action> handleComponent(String id)
throws DTFException {
long start = System.currentTimeMillis();
ArrayList<Action> result = new ArrayList<Action>();
StorageFactory sf = Action.getStorageFactory();
HashMap<String, StorageIntf> storages = sf.getStorages();
HashMap<String, HashMap<String,Long>> sentfiles = getSent(id);
ArrayList<String> sentstorages = getStorages(id);
Iterator<Entry<String,StorageIntf>> entries =
storages.entrySet().iterator();
boolean exported = false;
while ( entries.hasNext() ) {
Entry<String,StorageIntf> entry = entries.next();
String key = entry.getKey();
StorageIntf storage = entry.getValue();
if ( !storage.isExportable() )
continue;
exported = true;
String cid = Action.getLocalID();
if ( !DTFNode.getType().equals(DTFConstants.DTFX_ID) )
cid = DTFNode.getOwner().getId();
if ( !sentstorages.contains(key) ) {
// this storage has not been created on the component mentioned.
Createstorage cs = new Createstorage();
cs.setId(key);
cs.setPath(storage.getPath());
cs.setExport("true");
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("Creating storage [" + key +
"] on [" + id + "]");
}
StorageStateUpdater ssu =
new StorageStateUpdater(cid,
storage.getId());
result.add(cs);
result.add(ssu);
sentstorages.add(key);
} else {
if ( Action.getLogger().isDebugEnabled() )
Action.getLogger().debug(id + " already has storage [" +
key + "]");
}
HashMap<String,Long> sfiles = sentfiles.get(key);
if ( sfiles == null ) {
sfiles = new HashMap<String,Long>();
sentfiles.put(key, sfiles);
}
String[] files = storage.getFiles();
if ( files != null ) {
if ( files.length == 0 ) {
if ( Action.getLogger().isDebugEnabled() )
Action.getLogger().debug("[" + storage +
"] storage is empty.");
}
for (int i = 0; i < files.length; i++) {
Long l = sfiles.get(files[i]);
Long m = storage.getLastModified(files[i]);
if ( l == null || l < m ) {
String sid = storage.getId();
String uri = "storage://" + sid + "/" + files[i];
PullFile pf = new PullFile();
if ( DTFNode.getType().equals("dtfa") )
pf.setOwner(DTFNode.getOwner().getOwner());
pf.setRemotefile(storage.getFullPath() + "/" + files[i]);
pf.setUri(uri);
pf.setTo(Action.getLocalID());
if ( DTFNode.getType().equals(DTFConstants.DTFX_ID) ) {
pf.setAppend("false");
} else {
pf.setAppend("" + storage.openedAsAppend(files[i]));
pf.setOffset(storage.lastOpenedOffset(files[i]));
}
StorageFileUpdater sfu =
new StorageFileUpdater(cid, sid, files[i]);
result.add(pf);
result.add(sfu);
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("sending file [" + uri +
"] to [" + id +
"] modified [" + m +
"] append [" +
pf.getAppend() + "]");
}
sfiles.put(files[i], m);
} else {
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("not sending file [" +
files[i] + "] to [" +
id + "] modified [" + m +
"] synced at [" + l + "]");
}
}
}
} else {
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("[" + storage +
"] storage is empty.");
}
}
}
long stop = System.currentTimeMillis();
if ( Action.getLogger().isDebugEnabled() && exported ) {
long dur = (stop-start);
Action.getLogger().debug("Time to sync storages: " + dur + "ms");
}
return result;
}
public ArrayList<Action> returnToRunner(String id) throws DTFException {
ArrayList<Action> result = handleComponent(id);
return result;
}
public static void updateStorage(String componentid, String storageid) {
ArrayList<String> sentstorages = getStorages(componentid);
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("Updated storage [" + storageid +
"] for [" + componentid + "]");
}
sentstorages.add(storageid);
}
public static void updateLastModified(String componentid,
String storageid,
String filename) {
StorageFactory sf = Action.getStorageFactory();
StorageIntf storage = sf.getStorages().get(storageid);
Long m = storage.getLastModified(filename);
// get all storages and files that were sent to this componentid
HashMap<String, HashMap<String,Long>> sentfiles = getSent(componentid);
// only the specific files that were sent for this storageid
HashMap<String, Long> sfiles = sentfiles.get(storageid);
if ( sfiles == null ) {
sfiles = new HashMap<String, Long>();
sentfiles.put(storageid, sfiles);
}
if ( Action.getLogger().isDebugEnabled() ) {
Action.getLogger().debug("Updating [" + storageid + ": " +
filename + "] for [" + componentid +
"] modified at [" + m + "]");
}
// simply update the last modified so we have a starting point
sfiles.put(filename, m);
}
public void unlockComponent(String id) throws DTFException {
HashMap<String, HashMap<String,Long>> sentfiles = getSent(id);
ArrayList<String> sentstorages = getStorages(id);
if ( sentstorages != null )
sentstorages.clear();
if ( sentfiles != null )
sentfiles.clear();
}
public void cleanup() throws DTFException {
Action.unRegisterGlobalContext(SSFILES);
Action.unRegisterGlobalContext(SSSTORAGE);
}
}