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 true; }

  @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;
    }
  }

}

@@ -2581,11 +2581,12 @@
 urn 
-tru
+fals
 e; %7D

Stop logging RPC to DKV. Might speed up stuff.