package water;
/** 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) {
fs.add(RPC.call(h2o,new TaskPutKey(key,val,dontCache)));
}
protected TaskPutKey( Key key, Value val ) { this(key,val,false);}
protected TaskPutKey( Key key, Value val, boolean removeCache ) { super(H2O.PUT_KEY_PRIORITY); _xkey = _key = key; _xval = _val = val; _dontCache = removeCache;}
protected TaskPutKey( Key key ) { super(H2O.INVALIDATE_PRIORITY); _xkey = _key = key; _xval = _val = null; _dontCache = false;}
@Override public void dinvoke( H2ONode sender ) {
assert _key.home() || _val==null; // Only PUT to home for keys, or remote invalidation from home
Paxos.lockCloud(_key);
// Initialize Value for having a single known replica (the sender)
if( _val != null ) _val.initReplicaHome(sender,_key);
else if( _key.home() ) _val = Value.makeNull(_key);
// Spin, until we update something.
Value old = H2O.STORE.get(_key); // Raw-get: do not lazy-manifest if overwriting
while( H2O.putIfMatch(_key,_val,old) != old )
old = H2O.STORE.get(_key); // Repeat until we update something.
// Invalidate remote caches. Block, so that all invalidates are done
// before we return to the remote caller. This is conservative, but
// otherwise we have to send the invalidate-completion message to the
// remote caller; i.e. the caller would have to handle a 2-step Put
// completion ("I started your Put request" and "I completed your Put
// request").
if( _key.home() ) {
if( old != null ) old.lockAndInvalidate(sender,_val,new Futures()).blockForPending();
else _val.lowerActiveGetCount(null); // Remove initial read-lock, accounting for pending inv counts
}
// No return result
_key = null;
_val = null;
tryComplete();
}
@Override public void compute2() { throw H2O.fail(); }
// 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();
}
}