package com.zillabyte.motherbrain.flow.local;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.codehaus.plexus.util.ExceptionUtils;
import org.javatuples.Triplet;
import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Throwables;
import com.zillabyte.motherbrain.flow.MapTuple;
import com.zillabyte.motherbrain.flow.collectors.OutputCollector;
import com.zillabyte.motherbrain.flow.collectors.coordinated.CoordinatedOutputCollector;
import com.zillabyte.motherbrain.flow.collectors.coordinated.ObserveIncomingTupleAction;
import com.zillabyte.motherbrain.flow.operations.Join;
import com.zillabyte.motherbrain.flow.operations.Operation;
import com.zillabyte.motherbrain.flow.operations.OperationException;
import com.zillabyte.motherbrain.flow.operations.ProcessableOperation;
import com.zillabyte.motherbrain.flow.operations.Source;
import com.zillabyte.motherbrain.utils.Utils;
public class LocalOperationSlot {
private Operation _operation;
private OutputCollector _collector;
private Integer _taskId = -1;
private LinkedBlockingQueue<Triplet<Integer, String, Object>> _queue = new LinkedBlockingQueue<>();
private LocalFlowController _controller;
private Future<Void> _future;
private static Logger _log = Utils.getLogger(LocalOperationSlot.class);
public LocalOperationSlot(Operation o, Integer taskId, LocalFlowController controller) {
_operation = o;
_taskId = taskId;
_collector = new CoordinatedOutputCollector(new LocalFlowOutputCollector(this));
_controller = controller;
}
public void prepare() {
try {
_collector.configure(null);
_operation.handlePrepare(_collector);
} catch (OperationException | InterruptedException e) {
Throwables.propagate(e);
}
}
public boolean isRunning() {
if (_future != null) {
return !_future.isDone();
}
return false;
}
public void start() {
if (_future != null) throw new IllegalStateException("future already exists!");
_future = Utils.run(new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
while(true) {
// Exit check..
if (Thread.interrupted()) break;
// Source emit check...
if (_operation instanceof Source) {
((Source)_operation).handleNextTuple(_collector);
}
// Incoming tuple check...
Triplet<Integer, String, Object> triplet = _queue.poll(1, TimeUnit.MILLISECONDS);
if (triplet == null) continue;
debug("popping local tuple: " + triplet.getValue2());
// INIT
Integer fromTask = triplet.getValue0();
String onStream = triplet.getValue1();
Object rawTuple = triplet.getValue2();
Object tuple = null;
if (rawTuple instanceof List) {
tuple = ((List)rawTuple).get(0);
} else {
tuple = rawTuple;
}
if (_collector.observePreQueuedCoordTuple(tuple, fromTask) == ObserveIncomingTupleAction.STOP)
continue;
if (_collector.observePostQueuedCoordTuple(tuple, fromTask) == ObserveIncomingTupleAction.STOP)
continue;
// Process the next item...
if (_operation instanceof ProcessableOperation) {
if (_operation instanceof Join) {
((Join) _operation).handleProcess((MapTuple) tuple, onStream, _collector);
} else {
((ProcessableOperation)_operation).handleProcess((MapTuple) tuple, _collector);
}
} else {
throw new IllegalStateException("unexpected operation type: " + _operation);
}
_collector.onAfterTuplesEmitted();
}
} catch(InterruptedException e) {
// Do nothing...
} catch(Exception e) {
debug(ExceptionUtils.getFullStackTrace(e));
_log.error(e.getMessage());
_controller.handleSlotError(LocalOperationSlot.this, e);
Throwables.propagate(e);
}
return null;
}
});
}
public void stop() {
try {
_operation.cleanup();
if (_future != null) {
_future.cancel(true);
_future = null;
}
this._queue.clear();
} catch(Exception e) {
Throwables.propagate(e);
}
}
public void enqueueTuple(Integer sourceTask, String stream, Object tuple) {
debug("queueing local tuple: " + tuple);
_queue.add(new Triplet<>(sourceTask, stream, tuple));
}
public Integer task() {
return this._taskId;
}
public Operation operation() {
return this._operation;
}
public LocalFlowController controller() {
return this._controller;
}
private void debug(String s) {
// System.err.println(s);
}
}