package water;
import java.util.concurrent.Future;
import water.DTask;
/**
* Push the given key to the remote node
*
* @author <a href="mailto:cliffc@h2o.ai"></a>
* @version 1.0
*/
public class TaskPutKey extends DTask<TaskPutKey> {
Key _key;
Value _val;
boolean _dontCache; // delete cached value on the sender's side?
transient Value _xval;
transient Key _xkey;
static void put( H2ONode h2o, Key key, Value val, Futures fs, boolean dontCache) {
Future f = RPC.call(h2o,new TaskPutKey(key,val,dontCache));
if( fs != null ) fs.add(f);
}
protected TaskPutKey( Key key, Value val ) { this(key,val,false);}
protected TaskPutKey( Key key, Value val, boolean removeCache ) { _xkey = _key = key; _xval = _val = val; _dontCache = removeCache;}
@Override public void dinvoke( H2ONode sender ) {
assert _key.home() || _val==null; // Only PUT to home for keys, or remote invalidation from home
Paxos.lockCloud();
// Initialize Value for having a single known replica (the sender)
if( _val != null ) _val.initReplicaHome(sender,_key);
// Spin, until we update something.
Value old = H2O.raw_get(_key); // Raw-get: do not lazy-manifest if overwriting
while( H2O.putIfMatch(_key,_val,old) != old )
old = H2O.raw_get(_key); // Repeat until we update something.
// Invalidate remote caches. Block, so that all invalidates are done
// before we return to the remote caller.
if( _key.home() && old != null )
old.lockAndInvalidate(sender,new Futures()).blockForPending();
// No return result
_key = null;
_val = null;
tryComplete();
}
@Override public void compute2() { throw H2O.unimpl(); }
// Received an ACK
@Override public void onAck() {
// remove local cache but NOT in case it is already on disk
// (ie memory can be reclaimed and we assume we have plenty of disk space)
if( _dontCache && !_xval.isPersisted() ) H2O.putIfMatch(_xkey, null, _xval);
if( _xval != null ) _xval.completeRemotePut();
}
@Override public byte priority() {
return H2O.PUT_KEY_PRIORITY;
}
}