package water;
import jsr166y.CountedCompleter;
import water.DException.DistributedException;
import water.H2O.H2OCountedCompleter;
/** Objects which are passed and remotely executed.<p>
* <p>
* Efficient serialization methods for subclasses will be automatically
* generated, but explicit ones can be provided. Transient fields will
* <em>not</em> be mirrored between the VMs.
* <ol>
* <li>On the local vm, this task will be serialized and sent to a remote.</li>
* <li>On the remote, the task will be deserialized.</li>
* <li>On the remote, the H2ONode invoke method will be executed.</li>
* <li>On the remote, the task will be serialized and sent to the local vm</li>
* <li>On the local vm, the task will be deserialized
* <em>into the original instance</em></li>
* <li>On the local vm, the {@link #onAck()} method will be executed.</li>
* <li>On the remote, the {@link #onAckAck()} method will be executed.</li>
* </ol>
*
*/
public abstract class DTask<T extends DTask> extends H2OCountedCompleter implements Freezable {
protected DTask(){}
public DTask(H2OCountedCompleter completer){super(completer);}
// Return a distributed-exception
protected DException _ex;
public final boolean hasException() { return _ex != null; }
public synchronized void setException(Throwable ex) { if( _ex==null ) _ex = new DException(ex); }
public DistributedException getDException() { return _ex==null ? null : _ex.toEx(); }
// Track if the reply came via TCP - which means a timeout on ACKing the TCP
// result does NOT need to get the entire result again, just that the client
// needs more time to process the TCP result.
transient boolean _repliedTcp; // Any return/reply/result was sent via TCP
/** Top-level remote execution hook. Called on the <em>remote</em>. */
public void dinvoke( H2ONode sender ) { compute2(); }
/** 2nd top-level execution hook. After the primary task has received a
* result (ACK) and before we have sent an ACKACK, this method is executed on
* the <em>local vm</em>. Transients from the local vm are available here. */
public void onAck() {}
/** 3rd top-level execution hook. After the original vm sent an ACKACK, this
* method is executed on the <em>remote</em>. Transients from the remote vm
* are available here. */
public void onAckAck() {}
/** Override to remove 2 lines of logging per RPC. 0.5M RPC's will lead to
* 1M lines of logging at about 50 bytes/line produces 50M of log file,
* which will swamp all other logging output. */
public boolean logVerbose() { return false; }
@Override public AutoBuffer write(AutoBuffer bb) { return bb.put(_ex); }
@Override public <T extends Freezable> T read(AutoBuffer bb) { _ex = bb.get(); return (T)this; }
@Override public <F extends Freezable> F newInstance() { throw barf("newInstance"); }
@Override public int frozenType() {throw barf("frozenType");}
@Override public AutoBuffer writeJSONFields(AutoBuffer bb) { return bb; }
@Override public water.api.DocGen.FieldDoc[] toDocField() { return null; }
public void copyOver(Freezable other) {
DTask that = (DTask)other;
this._ex = that._ex; // Copy verbatim semantics, replacing all fields
}
private RuntimeException barf(String method) {
return new RuntimeException(H2O.SELF + ":" + getClass().toString()+ " " + method + " should be automatically overridden in the subclass by the auto-serialization code");
}
/**
* Task to be executed at home of the given key.
* Basically a wrapper around DTask which enables us to bypass
* remote/local distinction (RPC versus submitTask).
*/
public static abstract class DKeyTask<T extends DKeyTask,V extends Iced> extends DTask<DKeyTask>{
private final Key _key;
public DKeyTask(final Key k) {this(null,k);}
public DKeyTask(H2OCountedCompleter cmp,final Key k) {
super(cmp);
_key = k;
}
// override this
protected abstract void map(V v);
@Override public final void compute2(){
if(_key.home()){
Value val = H2O.get(_key);
if(val != null) {
V v = val.get();
map(v);
}
tryComplete();
} else new RPC(_key.home_node(),this).addCompleter(this).call();
}
// onCompletion must be empty here, may be invoked twice (on remote and local)
@Override public void onCompletion(CountedCompleter cc){}
public void submitTask() {H2O.submitTask(this);}
public void forkTask() {fork();}
public T invokeTask() {
H2O.submitTask(this);
join();
return (T)this;
}
}
}