/******************************************************************************* * Copyright (c) 2013 Imperial College London. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Raul Castro Fernandez - initial design and implementation ******************************************************************************/ package uk.ac.imperial.lsds.seep.operator; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.imperial.lsds.seep.comm.routing.Router; import uk.ac.imperial.lsds.seep.comm.serialization.DataTuple; import uk.ac.imperial.lsds.seep.processingunit.IProcessingUnit; import uk.ac.imperial.lsds.seep.processingunit.StatefulProcessingUnit; import uk.ac.imperial.lsds.seep.state.StateWrapper; public class Operator implements Serializable, EndPoint, Connectable, Callback{ private static final long serialVersionUID = 1L; private final Logger LOG = LoggerFactory.getLogger(Operator.class); private final int operatorId; private int originalOpId; private final OperatorCode operatorCode; private final StateWrapper stateWrapper; private OperatorContext opContext = new OperatorContext(); private boolean ready = false; public IProcessingUnit processingUnit = null; private Router router = null; private Map<Integer, InputDataIngestionMode> inputDataIngestionMode = new HashMap<Integer, InputDataIngestionMode>(); public static Operator getStatefulOperator(int opId, OperatorCode opCode, StateWrapper s, List<String> attributes){ return new Operator(opId, opCode, s, attributes); } public static Operator getStatelessOperator(int opId, OperatorCode opCode, List<String> attributes){ return new Operator(opId, opCode, attributes); } public OperatorCode getOperatorCode(){ return operatorCode; } private Operator(int opId, OperatorCode opCode, List<String> attributes){ this.operatorId = opId; this.operatorCode = opCode; this.stateWrapper = null; opContext.setDeclaredWorkingAttributes(attributes); this.originalOpId = opId; } private Operator(int opId, OperatorCode opCode, StateWrapper s, List<String> attributes){ this.operatorId = opId; this.operatorCode = opCode; this.stateWrapper = s; opContext.setDeclaredWorkingAttributes(attributes); this.originalOpId = opId; } public void setOriginalOpId(int x){ originalOpId = x ; } public int getOriginalOpId(){ return originalOpId; } /** Other methods **/ public StateWrapper getStateWrapper(){ return stateWrapper; } public void setReady(boolean ready){ this.ready = ready; } public boolean getReady(){ return ready; } public Router getRouter(){ return router; } public void setRouter(Router router){ this.router = router; } public void setProcessingUnit(IProcessingUnit processingUnit){ this.processingUnit = processingUnit; this.operatorCode.api.setCallbackObject(this); } /** Methods used by the developers to send data **/ // Send downstream in round robin fashion public synchronized void send(DataTuple dt){ // We check the targets with our routers ArrayList<Integer> targets = router.forward(dt); processingUnit.sendData(dt, targets); } // Send to a particular downstream index public synchronized void send_toIndex(DataTuple dt, int idx){ ArrayList<Integer> targets = new ArrayList<Integer>(); targets.add(idx); processingUnit.sendData(dt, targets); } public synchronized void send_toIndices(DataTuple[] dts, int[] idxs){ ArrayList<Integer> targets = new ArrayList<>(); for(int idx : idxs){ targets.add(idx); } processingUnit.sendPartitionedData(dts, targets); } // Send downstream to stateful partitionable operator public synchronized void send_splitKey(DataTuple dt, int key){ // We check the targets with our routers ArrayList<Integer> targets = router.forward_splitKey(dt, key); processingUnit.sendData(dt, targets); } // Send to specific streamId in round robin public synchronized void send_toStreamId(DataTuple dt, int streamId){ ArrayList<Integer> targets = router.forward_toOp(dt, streamId); processingUnit.sendData(dt, targets); } // Send to stateful partition of a given streamId public synchronized void send_toStreamId_splitKey(DataTuple dt, int streamId, int key){ ArrayList<Integer> targets = router.forward_toOp_splitKey(dt, streamId, key); processingUnit.sendData(dt, targets); } // Send to all instances of a specific streamId public synchronized void send_toStreamId_toAll(DataTuple dt, int streamId){ ArrayList<Integer> targets = router.forwardToAllOpsInStreamId(dt, streamId); processingUnit.sendData(dt, targets); } // Send to all downstream public void send_all(DataTuple dt){ // When routing to all, targets are all the logical downstreamoperators ArrayList<Integer> targets = router.forwardToAllDownstream(dt); processingUnit.sendData(dt, targets); } public synchronized void send_toStreamId_toAll_threadPool(DataTuple dt, int streamId){ ArrayList<Integer> targets = router.forwardToAllOpsInStreamId(dt, streamId); processingUnit.sendDataByThreadPool(dt, targets); } public void send_all_threadPool(DataTuple dt){ // When routing to all, targets are all the logical downstreamoperators ArrayList<Integer> targets = router.forwardToAllDownstream(dt); processingUnit.sendDataByThreadPool(dt, targets); } /** System Configuration Settings **/ public void disableCheckpointing(){ // Disable checkpointing the state for operator with operatorId ((StatefulProcessingUnit)processingUnit).disableCheckpointForOperator(operatorId); } public void disableMultiCoreSupport(){ processingUnit.disableMultiCoreSupport(); } /** Data Delivery methods **/ public InputDataIngestionMode getInputDataIngestionModeForUpstream(int opId){ return inputDataIngestionMode.get(opId); } public Map<Integer, InputDataIngestionMode> getInputDataIngestionModeMap(){ return inputDataIngestionMode; } public void setInputDataIngestionModeForUpstream(int opId, InputDataIngestionMode mode){ this.inputDataIngestionMode.put(opId, mode); } /** Implementation of QuerySpecificationI **/ public int getOperatorId(){ return operatorId; } public OperatorContext getOpContext(){ return opContext; } public void setOpContext(OperatorContext opContext){ this.opContext = opContext; } public void setOriginalDownstream(ArrayList<Integer> originalDownstream){ this.opContext.setOriginalDownstream(originalDownstream); } public void _declareWorkingAttributes(List<String> attributes){ opContext.setDeclaredWorkingAttributes(attributes); } public void _declareWorkingAttributes(List<String> attributes, String key){ opContext.setKeyAttribute(key); opContext.setDeclaredWorkingAttributes(attributes); } public void initializeInputDataIngestionModePerUpstream(Map<Integer, InputDataIngestionMode> idim){ for(Integer opId : idim.keySet()){ this.getOpContext().setInputDataIngestionModePerUpstream(opId, idim.get(opId)); } } public void processData(DataTuple data){ operatorCode.processData(data); } public void processData(ArrayList<DataTuple> dataList){ operatorCode.processData(dataList); } public void setUp(){ operatorCode.setUp(); } @Override public void connectTo(Connectable down, boolean originalQuery) { // default inputdataingestion and default stream this.connectTo(down, InputDataIngestionMode.ONE_AT_A_TIME, originalQuery, 0); } @Override public void connectTo(Connectable down, boolean originalQuery, int streamId) { // default inputdataingestion this.connectTo(down, InputDataIngestionMode.ONE_AT_A_TIME, originalQuery, streamId); } @Override public void connectTo(Connectable down, InputDataIngestionMode mode, boolean originalQuery, int streamId) { LOG.debug("Connecting OP: "+this.getOperatorId()+" with downstream Op: "+down.getOperatorId()); opContext.addDownstream(down.getOperatorId()); if(originalQuery) opContext.addOriginalDownstream(down.getOperatorId()); down.getOpContext().addUpstream(getOperatorId()); // We store routing info, an operator sends to a streamId, who knows the end-stream edge opContext.routeValueToDownstream(streamId, down.getOperatorId()); // Store in the opContext of the downstream I am adding, the inputdataingestion mode that I demand this.setInputDataIngestionModeForUpstream(down.getOperatorId(), mode); } /** HELPER METHODS **/ @Override public String toString() { return "Operator [operatorId="+operatorId+", opContext= "+opContext+"]"; } }