package water;
import jsr166y.CountedCompleter;
import jsr166y.RecursiveAction;
import java.util.concurrent.CancellationException;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* Created by tomas on 11/5/16.
*
* Generic lightewight Local MRTask utility. Will launch requested number of tasks (on local node!), organized in a binary tree fashion, similar to MRTask.
* Will attempt to share local results (MrFun instances) if the previous task has completed before launching current task.
*
* User expected to pass in MrFun implementing map(id), reduce(MrFun) and makeCopy() functions.
* At the end of the task, MrFun holds the result.
*/
public class LocalMR<T extends MrFun<T>> extends H2O.H2OCountedCompleter<LocalMR> {
private int _lo;
private int _hi;
MrFun _mrFun;
volatile Throwable _t;
private volatile boolean _cancelled;
private LocalMR<T> _root;
public LocalMR(MrFun mrt, int nthreads){this(mrt,nthreads,null);}
public LocalMR(MrFun mrt, H2O.H2OCountedCompleter cc){this(mrt,H2O.NUMCPUS,cc);}
public LocalMR(MrFun mrt, int nthreads, H2O.H2OCountedCompleter cc){
super(cc);
if(nthreads <= 0)
throw new IllegalArgumentException("nthreads must be positive");
_root = this;
_mrFun = mrt; // used as golden copy and also will hold the result after task has finished.
_lo = 0;
_hi = nthreads;
_prevTsk = null;
}
private LocalMR(LocalMR src, LocalMR prevTsk,int lo, int hi) {
super(src);
_root = src._root;
_prevTsk = prevTsk;
_lo = lo;
_hi = hi;
_cancelled = src._cancelled;
}
private LocalMR<T> _left;
private LocalMR<T> _rite;
private final LocalMR<T> _prevTsk; //will attempt to share MrFun with "previous task" if it's done by the time we start
volatile boolean completed; // this task and all it's children completed
volatile boolean started; // this task and all it's children completed
public boolean isCancelRequested(){return _root._cancelled;}
private int mid(){ return _lo + ((_hi - _lo) >> 1);}
@Override
public final void compute2() {
started = true;
if(_root._cancelled){
tryComplete();
return;
}
int mid = mid();
assert _hi > _lo;
if (_hi - _lo >= 2) {
_left = new LocalMR(this, _prevTsk, _lo, mid);
if (mid < _hi) {
addToPendingCount(1);
(_rite = new LocalMR(this, _left, mid, _hi)).fork();
}
_left.compute2();
} else {
if(_prevTsk != null && _prevTsk.completed){
_mrFun = _prevTsk._mrFun;
_prevTsk._mrFun = null;
} else if(this != _root)
_mrFun = _root._mrFun.makeCopy();
try {
_mrFun.map(mid);
} catch (Throwable t) {
if (_root._t == null) {
_root._t = t;
_root._cancelled = true;
}
}
tryComplete();
}
}
@Override
public final void onCompletion(CountedCompleter cc) {
try {
if (_cancelled) {
assert this == _root;
completeExceptionally(_t == null ? new CancellationException() : _t); // instead of throw
return;
}
if (_root._cancelled) return;
if (_left != null && _left._mrFun != null && _mrFun != _left._mrFun) {
assert _left.completed;
if (_mrFun == null) _mrFun = _left._mrFun;
else _mrFun.reduce(_left._mrFun);
}
if (_rite != null && _mrFun != _rite._mrFun) {
assert _rite.completed;
if (_mrFun == null) _mrFun = _rite._mrFun;
else _mrFun.reduce(_rite._mrFun);
}
_left = null;
_rite = null;
completed = true;
} catch(Throwable t){
if(this == _root){
completeExceptionally(t); // instead of throw
} else if (_root._t == null) {
_root._t = t;
_root._cancelled = true;
}
}
}
}