All Downloads are FREE. Search and download functionalities are using the official Maven repository.

water.rapids.Env Maven / Gradle / Ivy

There is a newer version: 3.8.2.9
Show newest version
package water.rapids;

import water.*;
import water.fvec.Frame;

import java.io.Closeable;
import java.util.ArrayList;

/** Execute a set of instructions in the context of an H2O cloud.
 *
 *  An Env (environment) object is a classic stack of values used during
 *  execution of an AST.  The stack is hidden in the normal Java execution
 *  stack and is not explicit.
 *
 *  For efficiency, reference counting is employed to recycle objects already
 *  in use rather than creating copies upon copies (a la R).  When a Frame is
 *  `pushed` on to the stack, its reference count is incremented by 1.  When a
 *  Frame is `popped` off of the stack, its reference count is decremented by
 *  1.  When the reference count is 0, the Env instance will dispose of the
 *  object.  All objects live and die by the Env's that create them.  That
 *  means that any object not created by an Env instance shalt not be
 *  DKV.removed.
 *
 *  Therefore, the Env class is a stack of values + an API for reference counting.
 */
public class Env extends Iced {

  // Session holds the ref-cnts across multiple executions.
  final Session _ses;
  public Env( Session ses ) { _ses = ses; }

  // Frames that are alive in mid-execution; usually because we have evaluated
  // some first expression and need to hang onto it while evaluating the next
  // expression.
  private ArrayList _stk  = new ArrayList<>();
  public int sp() { return _stk.size(); }
  private Frame peek(int x) { return _stk.get(sp()+x);  }

  // Deletes dead Frames & forces good stack cleanliness at opcode end.  One
  // per Opcode implementation.  Track frames that are alive mid-execution, but
  // dead at Opcode end.
  public StackHelp stk() { return new StackHelp(); }
  class StackHelp implements Closeable {
    final int _sp = sp();
    // Push & track.  Called on every Val that spans a (nested) exec call.
    // Used to track Frames with lifetimes spanning other AST executions.
    public Val track(Val v) {
      if( v instanceof ValFrame ) track(((ValFrame)v)._fr);
      return v; 
    }
    public Frame track(Frame fr) {
      _stk.add(sp(),new Frame(fr._names,fr.vecs().clone())); // Push and track a defensive copy
      return fr;
    }

    // Pop-all and remove dead.  If a Frame was not "tracked" above, then if it
    // goes dead it will leak on function exit.  If a Frame is returned from a
    // function and not declared "returning", any Vecs it shares with Frames
    // that are dying in this opcode will be deleted out from under it.
    @Override public void close() {
      Futures fs = null;
      int sp = sp();
      while( sp > _sp ) {
        Frame fr = _stk.remove(--sp); // Pop and stop tracking
        fs = _ses.downRefCnt(fr,fs);  // Refcnt -1 all Vecs, and delete if zero refs
      }
      if( fs != null ) fs.blockForPending();
    }

    // Pop last element and lower refcnts - but do not delete.  Lifetime is
    // responsibility of the caller.
    Val untrack(Val vfr) {
      if( !vfr.isFrame() ) return vfr;
      Frame fr = vfr.getFrame();
      _ses.addRefCnt(fr,-1);           // Lower counts, but do not delete on zero
      return vfr;
    }

  }

  // If an opcode is returning a Frame, it must call "returning(frame)" to
  // track the returned Frame.  Otherwise shared input Vecs who's last use is
  // in this opcode will get deleted as the opcode exits - even if they are
  // shared in the returning output Frame.
  public  V returning( V val ) {
    if( val instanceof ValFrame )
      _ses.addRefCnt(((ValFrame)val)._fr,1);
    return val;
  }

  // ----
  // Variable lookup

  ASTFun _scope;                // Current lexical scope lookup

  Val lookup( String id ) {
    // Lexically scoped functions first
    Val val = _scope==null ? null : _scope.lookup(id);
    if( val != null ) return val;

    // disallow TRUE/FALSE/NA to be overwritten by keys in the DKV... just way way saner this way
    if( id.equals("TRUE") || id.equals("FALSE") || id.equals("NA") || id.equals("NaN") ) {
      AST ast = AST.PRIMS.get(id);
      return ast.exec(this);
    }

    // Now the DKV
    Value value = DKV.get(Key.make(id));
    if( value != null ) {
      if( value.isFrame() )
        return addGlobals((Frame)value.get());
      // Only understand Frames right now
      throw new IllegalArgumentException("DKV name lookup of "+id+" yielded an instance of type "+value.className()+", but only Frame is supported");
    }

    // Now the built-ins
    AST ast = AST.PRIMS.get(id);
    if( ast != null )
      return ast instanceof ASTNum ? ast.exec(this) : new ValFun(ast);

    throw new IllegalArgumentException("Name lookup of '"+id+"' failed");
  }

  // Add these Vecs to the global list, and make a new defensive copy of the
  // frame - so we can hack it without changing the global frame view.
  ValFrame addGlobals( Frame fr ) {
    _ses.addGlobals(fr);
    return new ValFrame(new Frame(fr._names.clone(),fr.vecs().clone()));
  }

  /*
   * Utility & Cleanup
   */

  @Override public String toString() {
    String s="{";
    for( int i=0, sp=sp(); i < sp; i++ ) s += peek(-sp+i).toString()+",";
    return s+"}";
  }

  public AutoBuffer write_impl(AutoBuffer ab) {
    //ab.put4(_globals.size());   for( Vec vec : _globals ) ab.put(vec._key);
    //ab.put4(sp());              for( Frame fr : _stk ) ab.put(fr);
    //return ab;
    throw water.H2O.unimpl();
  }

  public Env read_impl(AutoBuffer ab) {
    //_globals = new HashSet<>();
    //int len=ab.get4();
    //for( int i=0; i();
    //len=ab.get4();
    //for( int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy