package uk.ac.imperial.lsds.seepworker.core; import static com.codahale.metrics.MetricRegistry.name; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.imperial.lsds.seep.api.API; import uk.ac.imperial.lsds.seep.api.SeepTask; import uk.ac.imperial.lsds.seep.api.data.ITuple; import uk.ac.imperial.lsds.seep.api.state.SeepState; import uk.ac.imperial.lsds.seep.core.InputAdapter; import uk.ac.imperial.lsds.seep.core.InputAdapterReturnType; import uk.ac.imperial.lsds.seep.metrics.SeepMetrics; import uk.ac.imperial.lsds.seepworker.WorkerConfig; import uk.ac.imperial.lsds.seepworker.core.Conductor.ConductorCallback; import uk.ac.imperial.lsds.seepworker.core.input.CoreInput; import uk.ac.imperial.lsds.seepworker.core.output.CoreOutput; import com.codahale.metrics.Meter; public class SingleThreadProcessingEngine implements ProcessingEngine { final private Logger LOG = LoggerFactory.getLogger(SingleThreadProcessingEngine.class.getName()); final private int MAX_BLOCKING_TIME_PER_INPUTADAPTER_MS; private boolean working = false; private Thread worker; private ConductorCallback callback; private int id; private CoreInput coreInput; private CoreOutput coreOutput; private SeepTask task; private SeepState state; // Metrics final private Meter m; public SingleThreadProcessingEngine(WorkerConfig wc, int id, SeepTask task, SeepState state, CoreInput coreInput, CoreOutput coreOutput, ConductorCallback callback) { this.id = id; this.task = task; this.state = state; this.coreInput = coreInput; this.coreOutput = coreOutput; this.callback = callback; this.MAX_BLOCKING_TIME_PER_INPUTADAPTER_MS = wc.getInt(WorkerConfig.MAX_WAIT_TIME_PER_INPUTADAPTER_MS); this.worker = new Thread(new Worker()); this.worker.setName(this.getClass().getSimpleName()); m = SeepMetrics.REG.meter(name(SingleThreadProcessingEngine.class, "event", "per", "sec")); } @Override public void start() { working = true; this.worker.start(); } @Override public void stop() { if(task != null) task.close(); // to avoid nullpointer when Ctrl^c after stopping query working = false; this.closeAndCleanEngine(); } private void closeAndCleanEngine(){ try { LOG.debug("Waiting for worker thread to die..."); worker.join(); LOG.debug("Waiting for worker thread to die...OK"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } coreInput = null; coreOutput = null; task = null; state = null; } private class Worker implements Runnable { @Override public void run() { List<InputAdapter> inputAdapters = coreInput.getInputAdapters(); LOG.info("Configuring SINGLETHREAD processing engine with {} inputAdapters", inputAdapters.size()); Iterator<InputAdapter> it = inputAdapters.iterator(); short one = InputAdapterReturnType.ONE.ofType(); short many = InputAdapterReturnType.MANY.ofType(); LOG.info("Configuring SINGLETHREAD processing engine with {} outputBuffers", coreOutput.getBuffers().size()); API api = new Collector(id, coreOutput); int ongoingStreams = inputAdapters.size(); while(working) { for(int i = 0; i < inputAdapters.size(); i++) { InputAdapter ia = inputAdapters.get(i); if(ia.returnType() == one) { ITuple d = ia.pullDataItem(MAX_BLOCKING_TIME_PER_INPUTADAPTER_MS); if(d != null) { task.processData(d, api); m.mark(); } else { // Exhausted IA ongoingStreams--; } } else if(ia.returnType() == many) { List<ITuple> d = ia.pullDataItems(MAX_BLOCKING_TIME_PER_INPUTADAPTER_MS); if(d != null) { task.processDataGroup(d, api); m.mark(); } else { // Exhausted IA ongoingStreams--; } } // Reset iteration before the last element if(i == inputAdapters.size()-1 && working) { i = -1; } if(! callback.isContinuousTask()) { if(ongoingStreams == 0) { task.close(); callback.notifyOk(api.getRuntimeEvents()); // notify and pass all generated runtime events working = false; i = inputAdapters.size(); } } } // If there are no input adapters, assume processData contain all necessary and give null input data if(working){ LOG.info("About to call processData without data. Am I a source?"); task.processData(null, api); working = false; // run source only once } } this.closeEngine(); } private boolean allStreamsFinished(Map<Integer, Boolean> tracker) { boolean finished = true; for(boolean f : tracker.values()) { finished = finished & f; } return finished; } private void closeEngine(){ LOG.info("Stopping main engine thread"); } } }