package uk.ac.imperial.lsds.seep.scheduler; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import uk.ac.imperial.lsds.seep.api.DataReference; import uk.ac.imperial.lsds.seep.infrastructure.ControlEndPoint; import uk.ac.imperial.lsds.seep.infrastructure.SeepEndPoint; import uk.ac.imperial.lsds.seep.util.Utils; public class Stage { private final int stageId; /** * Indicates the location where the stage *should* execute. * Maybe a scheduler can overwrite this info */ private ControlEndPoint location; /** * A stage can be of type source (first to execute), unique (only one in the schedule) * or a sink stage, that will output results. */ private StageType type; /** * Dependencies of this stage */ private Set<Stage> upstream; /** * This stage is a dependency of downstream stages */ private Set<Stage> downstream; /** * All input data references this stage must consume. These will be partitioned across available tasks */ private Map<Integer, Set<DataReference>> inputDataReferences; /** * All data references produced by this stage */ private Map<Integer, Set<DataReference>> outputDataReferences; /** * The logical operators that are part of this stage. */ private Deque<Integer> wrapping; /** * Whether this stage will create a partitioned output or not */ private boolean hasPartitionedState = false; private boolean hasMultipleInput = false; public Stage(int stageId) { this.stageId = stageId; this.upstream = new HashSet<>(); this.downstream = new HashSet<>(); this.inputDataReferences = new HashMap<>(); this.outputDataReferences = new HashMap<>(); this.wrapping = new ArrayDeque<>(); } public Stage() { this.stageId = 0; } public int getStageId(){ return stageId; } public ControlEndPoint getStageLocation() { return location; } public void add(int opId){ this.wrapping.push(opId); } public Deque<Integer> getWrappedOperators() { return wrapping; } public Map<Integer, Set<DataReference>> getInputDataReferences() { return inputDataReferences; } public void addInputDataReference(int streamId, Set<DataReference> dataReferences) { if(! this.inputDataReferences.containsKey(streamId)){ this.inputDataReferences.put(streamId, new HashSet<>()); } this.inputDataReferences.get(streamId).addAll(dataReferences); } public Map<Integer, Set<DataReference>> getOutputDataReferences() { return outputDataReferences; } public Set<SeepEndPoint> getInvolvedNodes() { // FIXME: cannot depend on DR, as these can be external, i.e. no endpoint inside // FIXME: NEW -> what about location attribute? Set<SeepEndPoint> in = new HashSet<>(); for(Set<DataReference> drs : inputDataReferences.values()) { for(DataReference dr : drs) { in.add(dr.getControlEndPoint()); } } return in; } public boolean responsibleFor(int opId) { return wrapping.contains(opId); } public int getIdOfOperatorBoundingStage(){ return wrapping.peek(); } public void setHasPartitionedState(){ this.hasPartitionedState = true; } public boolean hasPartitionedState(){ return hasPartitionedState; } public boolean hasDependantWithPartitionedStage() { for(Stage s : this.downstream) { if (s.hasPartitionedState()) { return true; } } return false; } public void setRequiresMultipleInput(){ this.hasMultipleInput = true; } public boolean hasMultipleInput(){ return hasMultipleInput; } public void setStageLocation(ControlEndPoint location) { this.location = location; } public void setStageType(StageType type){ this.type = type; } public StageType getStageType(){ return type; } public void dependsOn(Stage stage) { upstream.add(stage); stage.downstream.add(this); } public Set<Stage> getDependencies(){ return upstream; } public Set<Stage> getDependants() { return downstream; } @Override public int hashCode(){ return stageId; } @Override public String toString(){ StringBuffer sb = new StringBuffer(); sb.append("StageId: "+stageId); sb.append(Utils.NL); sb.append("Type: "+type.toString()); sb.append(Utils.NL); sb.append("Wraps these operators: "); sb.append(Utils.NL); for(Integer opId : wrapping){ sb.append(" op -> "+opId); sb.append(Utils.NL); } sb.append(Utils.NL); sb.append("DependsOn: "); sb.append(Utils.NL); for(Stage s : upstream){ sb.append(" st -> "+s.stageId); sb.append(Utils.NL); } sb.append("Serves: "); sb.append(Utils.NL); for(Stage s : downstream){ sb.append(" st -> "+s.stageId); sb.append(Utils.NL); } return sb.toString(); } }