/*********************************************************************************************************************** * Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. **********************************************************************************************************************/ package eu.stratosphere.nephele.executiongraph; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import eu.stratosphere.nephele.taskmanager.TaskKillResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import eu.stratosphere.nephele.deployment.ChannelDeploymentDescriptor; import eu.stratosphere.nephele.deployment.GateDeploymentDescriptor; import eu.stratosphere.nephele.deployment.TaskDeploymentDescriptor; import eu.stratosphere.nephele.execution.ExecutionListener; import eu.stratosphere.nephele.execution.ExecutionState; import eu.stratosphere.nephele.execution.ExecutionStateTransition; import eu.stratosphere.nephele.instance.AllocatedResource; import eu.stratosphere.nephele.instance.AllocationID; import eu.stratosphere.runtime.io.gates.GateID; import eu.stratosphere.nephele.taskmanager.AbstractTaskResult; import eu.stratosphere.nephele.taskmanager.AbstractTaskResult.ReturnCode; import eu.stratosphere.nephele.taskmanager.TaskCancelResult; import eu.stratosphere.nephele.taskmanager.TaskSubmissionResult; import eu.stratosphere.nephele.util.AtomicEnum; import eu.stratosphere.nephele.util.SerializableArrayList; import eu.stratosphere.util.StringUtils; /** * An execution vertex represents an instance of a task in a Nephele job. An execution vertex * is initially created from a job vertex and always belongs to exactly one group vertex. * It is possible to duplicate execution vertices in order to distribute a task to several different * task managers and process the task in parallel. * <p> * This class is thread-safe. * */ public final class ExecutionVertex { /** * The log object used for debugging. */ private static final Log LOG = LogFactory.getLog(ExecutionVertex.class); /** * The ID of the vertex. */ private final ExecutionVertexID vertexID; /** * The group vertex this vertex belongs to. */ private final ExecutionGroupVertex groupVertex; /** * The execution graph is vertex belongs to. */ private final ExecutionGraph executionGraph; /** * The allocated resources assigned to this vertex. */ private final AtomicReference<AllocatedResource> allocatedResource = new AtomicReference<AllocatedResource>(null); /** * The allocation ID identifying the allocated resources used by this vertex * within the instance. */ private volatile AllocationID allocationID = null; /** * A list of {@link VertexAssignmentListener} objects to be notified about changes in the instance assignment. */ private final CopyOnWriteArrayList<VertexAssignmentListener> vertexAssignmentListeners = new CopyOnWriteArrayList<VertexAssignmentListener>(); /** * A map of {@link ExecutionListener} objects to be notified about the state changes of a vertex. */ private final ConcurrentMap<Integer, ExecutionListener> executionListeners = new ConcurrentSkipListMap<Integer, ExecutionListener>(); /** * The current execution state of the task represented by this vertex */ private final AtomicEnum<ExecutionState> executionState = new AtomicEnum<ExecutionState>(ExecutionState.CREATED); /** * The output gates attached to this vertex. */ private final ExecutionGate[] outputGates; /** * The input gates attached to his vertex. */ private final ExecutionGate[] inputGates; /** * The index of this vertex in the vertex group. */ private volatile int indexInVertexGroup = 0; /** * Stores the number of times the vertex may be still be started before the corresponding task is considered to be * failed. */ private final AtomicInteger retriesLeft; /** * The execution pipeline this vertex is part of. */ private final AtomicReference<ExecutionPipeline> executionPipeline = new AtomicReference<ExecutionPipeline>(null); /** * Flag to indicate whether the vertex has been requested to cancel while in state STARTING */ private final AtomicBoolean cancelRequested = new AtomicBoolean(false); /** * Create a new execution vertex and instantiates its environment. * * @param executionGraph * the execution graph the new vertex belongs to * @param groupVertex * the group vertex the new vertex belongs to * @param numberOfOutputGates * the number of output gates attached to this vertex * @param numberOfInputGates * the number of input gates attached to this vertex */ public ExecutionVertex(final ExecutionGraph executionGraph, final ExecutionGroupVertex groupVertex, final int numberOfOutputGates, final int numberOfInputGates) { this(new ExecutionVertexID(), executionGraph, groupVertex, numberOfOutputGates, numberOfInputGates); this.groupVertex.addInitialSubtask(this); } /** * Private constructor used to duplicate execution vertices. * * @param vertexID * the ID of the new execution vertex. * @param executionGraph * the execution graph the new vertex belongs to * @param groupVertex * the group vertex the new vertex belongs to * @param numberOfOutputGates * the number of output gates attached to this vertex * @param numberOfInputGates * the number of input gates attached to this vertex */ private ExecutionVertex(final ExecutionVertexID vertexID, final ExecutionGraph executionGraph, final ExecutionGroupVertex groupVertex, final int numberOfOutputGates, final int numberOfInputGates) { this.vertexID = vertexID; this.executionGraph = executionGraph; this.groupVertex = groupVertex; this.retriesLeft = new AtomicInteger(groupVertex.getNumberOfExecutionRetries()); this.outputGates = new ExecutionGate[numberOfOutputGates]; this.inputGates = new ExecutionGate[numberOfInputGates]; // Register vertex with execution graph this.executionGraph.registerExecutionVertex(this); // Register the vertex itself as a listener for state changes registerExecutionListener(this.executionGraph); } /** * Returns the group vertex this execution vertex belongs to. * * @return the group vertex this execution vertex belongs to */ public ExecutionGroupVertex getGroupVertex() { return this.groupVertex; } /** * Returns the name of the execution vertex. * * @return the name of the execution vertex */ public String getName() { return this.groupVertex.getName(); } /** * Returns a duplicate of this execution vertex. * * @param preserveVertexID * <code>true</code> to copy the vertex's ID to the duplicated vertex, <code>false</code> to create a new ID * @return a duplicate of this execution vertex */ public ExecutionVertex duplicateVertex(final boolean preserveVertexID) { ExecutionVertexID newVertexID; if (preserveVertexID) { newVertexID = this.vertexID; } else { newVertexID = new ExecutionVertexID(); } final ExecutionVertex duplicatedVertex = new ExecutionVertex(newVertexID, this.executionGraph, this.groupVertex, this.outputGates.length, this.inputGates.length); // Duplicate gates for (int i = 0; i < this.outputGates.length; ++i) { duplicatedVertex.outputGates[i] = new ExecutionGate(new GateID(), duplicatedVertex, this.outputGates[i].getGroupEdge(), false); } for (int i = 0; i < this.inputGates.length; ++i) { duplicatedVertex.inputGates[i] = new ExecutionGate(new GateID(), duplicatedVertex, this.inputGates[i].getGroupEdge(), true); } // TODO set new profiling record with new vertex id duplicatedVertex.setAllocatedResource(this.allocatedResource.get()); return duplicatedVertex; } /** * Inserts the output gate at the given position. * * @param pos * the position to insert the output gate * @param outputGate * the output gate to be inserted */ void insertOutputGate(final int pos, final ExecutionGate outputGate) { if (this.outputGates[pos] != null) { throw new IllegalStateException("Output gate at position " + pos + " is not null"); } this.outputGates[pos] = outputGate; } /** * Inserts the input gate at the given position. * * @param pos * the position to insert the input gate * @param outputGate * the input gate to be inserted */ void insertInputGate(final int pos, final ExecutionGate inputGate) { if (this.inputGates[pos] != null) { throw new IllegalStateException("Input gate at position " + pos + " is not null"); } this.inputGates[pos] = inputGate; } /** * Returns a duplicate of this execution vertex. The duplicated vertex receives * a new vertex ID. * * @return a duplicate of this execution vertex. */ public ExecutionVertex splitVertex() { return duplicateVertex(false); } /** * Returns this execution vertex's current execution status. * * @return this execution vertex's current execution status */ public ExecutionState getExecutionState() { return this.executionState.get(); } /** * Updates the vertex's current execution state through the job's executor service. * * @param newExecutionState * the new execution state * @param optionalMessage * an optional message related to the state change */ public void updateExecutionStateAsynchronously(final ExecutionState newExecutionState, final String optionalMessage) { final Runnable command = new Runnable() { /** * {@inheritDoc} */ @Override public void run() { updateExecutionState(newExecutionState, optionalMessage); } }; this.executionGraph.executeCommand(command); } /** * Updates the vertex's current execution state through the job's executor service. * * @param newExecutionState * the new execution state */ public void updateExecutionStateAsynchronously(final ExecutionState newExecutionState) { updateExecutionStateAsynchronously(newExecutionState, null); } /** * Updates the vertex's current execution state. * * @param newExecutionState * the new execution state */ public ExecutionState updateExecutionState(final ExecutionState newExecutionState) { return updateExecutionState(newExecutionState, null); } /** * Updates the vertex's current execution state. * * @param newExecutionState * the new execution state * @param optionalMessage * an optional message related to the state change */ public ExecutionState updateExecutionState(ExecutionState newExecutionState, final String optionalMessage) { if (newExecutionState == null) { throw new IllegalArgumentException("Argument newExecutionState must not be null"); } final ExecutionState currentExecutionState = this.executionState.get(); if (currentExecutionState == ExecutionState.CANCELING) { // If we are in CANCELING, ignore state changes to FINISHING if (newExecutionState == ExecutionState.FINISHING) { return currentExecutionState; } // Rewrite FINISHED to CANCELED if the task has been marked to be canceled if (newExecutionState == ExecutionState.FINISHED) { LOG.info("Received transition from CANCELING to FINISHED for vertex " + toString() + ", converting it to CANCELED"); newExecutionState = ExecutionState.CANCELED; } } // Check and save the new execution state final ExecutionState previousState = this.executionState.getAndSet(newExecutionState); if (previousState == newExecutionState) { return previousState; } // Check the transition ExecutionStateTransition.checkTransition(true, toString(), previousState, newExecutionState); // Notify the listener objects final Iterator<ExecutionListener> it = this.executionListeners.values().iterator(); while (it.hasNext()) { it.next().executionStateChanged(this.executionGraph.getJobID(), this.vertexID, newExecutionState, optionalMessage); } // The vertex was requested to be canceled by another thread checkCancelRequestedFlag(); return previousState; } public boolean compareAndUpdateExecutionState(final ExecutionState expected, final ExecutionState update) { if (update == null) { throw new IllegalArgumentException("Argument update must not be null"); } if (!this.executionState.compareAndSet(expected, update)) { return false; } // Check the transition ExecutionStateTransition.checkTransition(true, toString(), expected, update); // Notify the listener objects final Iterator<ExecutionListener> it = this.executionListeners.values().iterator(); while (it.hasNext()) { it.next().executionStateChanged(this.executionGraph.getJobID(), this.vertexID, update, null); } // Check if the vertex was requested to be canceled by another thread checkCancelRequestedFlag(); return true; } /** * Checks if another thread requested the vertex to cancel while it was in state STARTING. If so, the method clears * the respective flag and repeats the cancel request. */ private void checkCancelRequestedFlag() { if (this.cancelRequested.compareAndSet(true, false)) { final TaskCancelResult tsr = cancelTask(); if (tsr.getReturnCode() != AbstractTaskResult.ReturnCode.SUCCESS && tsr.getReturnCode() != AbstractTaskResult.ReturnCode.TASK_NOT_FOUND) { LOG.error("Unable to cancel vertex " + this + ": " + tsr.getReturnCode().toString() + ((tsr.getDescription() != null) ? (" (" + tsr.getDescription() + ")") : "")); } } } /** * Assigns the execution vertex with an {@link AllocatedResource}. * * @param allocatedResource * the resources which are supposed to be allocated to this vertex */ public void setAllocatedResource(final AllocatedResource allocatedResource) { if (allocatedResource == null) { throw new IllegalArgumentException("Argument allocatedResource must not be null"); } final AllocatedResource previousResource = this.allocatedResource.getAndSet(allocatedResource); if (previousResource != null) { previousResource.removeVertexFromResource(this); } allocatedResource.assignVertexToResource(this); // Notify all listener objects final Iterator<VertexAssignmentListener> it = this.vertexAssignmentListeners.iterator(); while (it.hasNext()) { it.next().vertexAssignmentChanged(this.vertexID, allocatedResource); } } /** * Returns the allocated resources assigned to this execution vertex. * * @return the allocated resources assigned to this execution vertex */ public AllocatedResource getAllocatedResource() { return this.allocatedResource.get(); } /** * Returns the allocation ID which identifies the resources used * by this vertex within the assigned instance. * * @return the allocation ID which identifies the resources used * by this vertex within the assigned instance or <code>null</code> if the instance is still assigned to a * {@link eu.stratosphere.nephele.instance.DummyInstance}. */ public AllocationID getAllocationID() { return this.allocationID; } /** * Returns the ID of this execution vertex. * * @return the ID of this execution vertex */ public ExecutionVertexID getID() { return this.vertexID; } /** * Returns the number of predecessors, i.e. the number of vertices * which connect to this vertex. * * @return the number of predecessors */ public int getNumberOfPredecessors() { int numberOfPredecessors = 0; for (int i = 0; i < this.inputGates.length; ++i) { numberOfPredecessors += this.inputGates[i].getNumberOfEdges(); } return numberOfPredecessors; } /** * Returns the number of successors, i.e. the number of vertices * this vertex is connected to. * * @return the number of successors */ public int getNumberOfSuccessors() { int numberOfSuccessors = 0; for (int i = 0; i < this.outputGates.length; ++i) { numberOfSuccessors += this.outputGates[i].getNumberOfEdges(); } return numberOfSuccessors; } public ExecutionVertex getPredecessor(int index) { if (index < 0) { throw new IllegalArgumentException("Argument index must be greather or equal to 0"); } for (int i = 0; i < this.inputGates.length; ++i) { final ExecutionGate inputGate = this.inputGates[i]; final int numberOfEdges = inputGate.getNumberOfEdges(); if (index >= 0 && index < numberOfEdges) { final ExecutionEdge edge = inputGate.getEdge(index); return edge.getOutputGate().getVertex(); } index -= numberOfEdges; } return null; } public ExecutionVertex getSuccessor(int index) { if (index < 0) { throw new IllegalArgumentException("Argument index must be greather or equal to 0"); } for (int i = 0; i < this.outputGates.length; ++i) { final ExecutionGate outputGate = this.outputGates[i]; final int numberOfEdges = outputGate.getNumberOfEdges(); if (index >= 0 && index < numberOfEdges) { final ExecutionEdge edge = outputGate.getEdge(index); return edge.getInputGate().getVertex(); } index -= numberOfEdges; } return null; } /** * Checks if this vertex is an input vertex in its stage, i.e. has either no * incoming connections or only incoming connections to group vertices in a lower stage. * * @return <code>true</code> if this vertex is an input vertex, <code>false</code> otherwise */ public boolean isInputVertex() { return this.groupVertex.isInputVertex(); } /** * Checks if this vertex is an output vertex in its stage, i.e. has either no * outgoing connections or only outgoing connections to group vertices in a higher stage. * * @return <code>true</code> if this vertex is an output vertex, <code>false</code> otherwise */ public boolean isOutputVertex() { return this.groupVertex.isOutputVertex(); } /** * Returns the index of this vertex in the vertex group. * * @return the index of this vertex in the vertex group */ public int getIndexInVertexGroup() { return this.indexInVertexGroup; } /** * Sets the vertex' index in the vertex group. * * @param indexInVertexGroup * the vertex' index in the vertex group */ void setIndexInVertexGroup(final int indexInVertexGroup) { this.indexInVertexGroup = indexInVertexGroup; } /** * Returns the number of output gates attached to this vertex. * * @return the number of output gates attached to this vertex */ public int getNumberOfOutputGates() { return this.outputGates.length; } /** * Returns the output gate with the given index. * * @param index * the index of the output gate to return * @return the output gate with the given index */ public ExecutionGate getOutputGate(final int index) { return this.outputGates[index]; } /** * Returns the number of input gates attached to this vertex. * * @return the number of input gates attached to this vertex */ public int getNumberOfInputGates() { return this.inputGates.length; } /** * Returns the input gate with the given index. * * @param index * the index of the input gate to return * @return the input gate with the given index */ public ExecutionGate getInputGate(final int index) { return this.inputGates[index]; } /** * Deploys and starts the task represented by this vertex * on the assigned instance. * * @return the result of the task submission attempt */ public TaskSubmissionResult startTask() { final AllocatedResource ar = this.allocatedResource.get(); if (ar == null) { final TaskSubmissionResult result = new TaskSubmissionResult(getID(), AbstractTaskResult.ReturnCode.NO_INSTANCE); result.setDescription("Assigned instance of vertex " + this.toString() + " is null!"); return result; } final List<TaskDeploymentDescriptor> tasks = new SerializableArrayList<TaskDeploymentDescriptor>(); tasks.add(constructDeploymentDescriptor()); try { final List<TaskSubmissionResult> results = ar.getInstance().submitTasks(tasks); return results.get(0); } catch (IOException e) { final TaskSubmissionResult result = new TaskSubmissionResult(getID(), AbstractTaskResult.ReturnCode.IPC_ERROR); result.setDescription(StringUtils.stringifyException(e)); return result; } } /** * Kills and removes the task represented by this vertex from the instance it is currently running on. If the * corresponding task is not in the state <code>RUNNING</code>, this call will be ignored. If the call has been * executed * successfully, the task will change the state <code>FAILED</code>. * * @return the result of the task kill attempt */ public TaskKillResult killTask() { final ExecutionState state = this.executionState.get(); if (state != ExecutionState.RUNNING) { final TaskKillResult result = new TaskKillResult(getID(), AbstractTaskResult.ReturnCode.ILLEGAL_STATE); result.setDescription("Vertex " + this.toString() + " is in state " + state); return result; } final AllocatedResource ar = this.allocatedResource.get(); if (ar == null) { final TaskKillResult result = new TaskKillResult(getID(), AbstractTaskResult.ReturnCode.NO_INSTANCE); result.setDescription("Assigned instance of vertex " + this.toString() + " is null!"); return result; } try { return ar.getInstance().killTask(this.vertexID); } catch (IOException e) { final TaskKillResult result = new TaskKillResult(getID(), AbstractTaskResult.ReturnCode.IPC_ERROR); result.setDescription(StringUtils.stringifyException(e)); return result; } } /** * Cancels and removes the task represented by this vertex * from the instance it is currently running on. If the task * is not currently running, its execution state is simply * updated to <code>CANCELLED</code>. * * @return the result of the task cancel attempt */ public TaskCancelResult cancelTask() { while (true) { final ExecutionState previousState = this.executionState.get(); if (previousState == ExecutionState.CANCELED) { return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } if (previousState == ExecutionState.FAILED) { return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } if (previousState == ExecutionState.FINISHED) { return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } // The vertex has already received a cancel request if (previousState == ExecutionState.CANCELING) { return new TaskCancelResult(getID(), ReturnCode.SUCCESS); } // Do not trigger the cancel request when vertex is in state STARTING, this might cause a race between RPC // calls. if (previousState == ExecutionState.STARTING) { this.cancelRequested.set(true); // We had a race, so we unset the flag and take care of cancellation ourselves if (this.executionState.get() != ExecutionState.STARTING) { this.cancelRequested.set(false); continue; } return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } // Check if we had a race. If state change is accepted, send cancel request if (compareAndUpdateExecutionState(previousState, ExecutionState.CANCELING)) { if (this.groupVertex.getStageNumber() != this.executionGraph.getIndexOfCurrentExecutionStage()) { // Set to canceled directly updateExecutionState(ExecutionState.CANCELED, null); return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } if (previousState != ExecutionState.RUNNING && previousState != ExecutionState.FINISHING) { // Set to canceled directly updateExecutionState(ExecutionState.CANCELED, null); return new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.SUCCESS); } final AllocatedResource ar = this.allocatedResource.get(); if (ar == null) { final TaskCancelResult result = new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.NO_INSTANCE); result.setDescription("Assigned instance of vertex " + this.toString() + " is null!"); return result; } try { return ar.getInstance().cancelTask(this.vertexID); } catch (IOException e) { final TaskCancelResult result = new TaskCancelResult(getID(), AbstractTaskResult.ReturnCode.IPC_ERROR); result.setDescription(StringUtils.stringifyException(e)); return result; } } } } /** * Returns the {@link ExecutionGraph} this vertex belongs to. * * @return the {@link ExecutionGraph} this vertex belongs to */ public ExecutionGraph getExecutionGraph() { return this.executionGraph; } @Override public String toString() { final StringBuilder sb = new StringBuilder(this.groupVertex.getName()); sb.append(" ("); sb.append(this.indexInVertexGroup + 1); sb.append('/'); sb.append(this.groupVertex.getCurrentNumberOfGroupMembers()); sb.append(')'); return sb.toString(); } /** * Returns the task represented by this vertex has * a retry attempt left in case of an execution * failure. * * @return <code>true</code> if the task has a retry attempt left, <code>false</code> otherwise */ @Deprecated public boolean hasRetriesLeft() { if (this.retriesLeft.get() <= 0) { return false; } return true; } /** * Decrements the number of retries left and checks whether another attempt to run the task is possible. * * @return <code>true</code>if the task represented by this vertex can be started at least once more, * <code>false/<code> otherwise */ public boolean decrementRetriesLeftAndCheck() { return (this.retriesLeft.decrementAndGet() > 0); } /** * Registers the {@link VertexAssignmentListener} object for this vertex. This object * will be notified about reassignments of this vertex to another instance. * * @param vertexAssignmentListener * the object to be notified about reassignments of this vertex to another instance */ public void registerVertexAssignmentListener(final VertexAssignmentListener vertexAssignmentListener) { this.vertexAssignmentListeners.addIfAbsent(vertexAssignmentListener); } /** * Unregisters the {@link VertexAssignmentListener} object for this vertex. This object * will no longer be notified about reassignments of this vertex to another instance. * * @param vertexAssignmentListener * the listener to be unregistered */ public void unregisterVertexAssignmentListener(final VertexAssignmentListener vertexAssignmentListener) { this.vertexAssignmentListeners.remove(vertexAssignmentListener); } /** * Registers the {@link ExecutionListener} object for this vertex. This object * will be notified about particular events during the vertex's lifetime. * * @param executionListener * the object to be notified about particular events during the vertex's lifetime */ public void registerExecutionListener(final ExecutionListener executionListener) { final Integer priority = Integer.valueOf(executionListener.getPriority()); if (priority.intValue() < 0) { LOG.error("Priority for execution listener " + executionListener.getClass() + " must be non-negative."); return; } final ExecutionListener previousValue = this.executionListeners.putIfAbsent(priority, executionListener); if (previousValue != null) { LOG.error("Cannot register " + executionListener.getClass() + " as an execution listener. Priority " + priority.intValue() + " is already taken."); } } /** * Unregisters the {@link ExecutionListener} object for this vertex. This object * will no longer be notified about particular events during the vertex's lifetime. * * @param executionListener * the object to be unregistered */ public void unregisterExecutionListener(final ExecutionListener executionListener) { this.executionListeners.remove(Integer.valueOf(executionListener.getPriority())); } /** * Sets the {@link ExecutionPipeline} this vertex shall be part of. * * @param executionPipeline * the execution pipeline this vertex shall be part of */ void setExecutionPipeline(final ExecutionPipeline executionPipeline) { final ExecutionPipeline oldPipeline = this.executionPipeline.getAndSet(executionPipeline); if (oldPipeline != null) { oldPipeline.removeFromPipeline(this); } executionPipeline.addToPipeline(this); } /** * Returns the {@link ExecutionPipeline} this vertex is part of. * * @return the execution pipeline this vertex is part of */ public ExecutionPipeline getExecutionPipeline() { return this.executionPipeline.get(); } /** * Constructs a new task deployment descriptor for this vertex. * * @return a new task deployment descriptor for this vertex */ public TaskDeploymentDescriptor constructDeploymentDescriptor() { final SerializableArrayList<GateDeploymentDescriptor> ogd = new SerializableArrayList<GateDeploymentDescriptor>( this.outputGates.length); for (int i = 0; i < this.outputGates.length; ++i) { final ExecutionGate eg = this.outputGates[i]; final List<ChannelDeploymentDescriptor> cdd = new ArrayList<ChannelDeploymentDescriptor>( eg.getNumberOfEdges()); final int numberOfOutputChannels = eg.getNumberOfEdges(); for (int j = 0; j < numberOfOutputChannels; ++j) { final ExecutionEdge ee = eg.getEdge(j); cdd.add(new ChannelDeploymentDescriptor(ee.getOutputChannelID(), ee.getInputChannelID())); } ogd.add(new GateDeploymentDescriptor(eg.getGateID(), eg.getChannelType(), cdd)); } final SerializableArrayList<GateDeploymentDescriptor> igd = new SerializableArrayList<GateDeploymentDescriptor>( this.inputGates.length); for (int i = 0; i < this.inputGates.length; ++i) { final ExecutionGate eg = this.inputGates[i]; final List<ChannelDeploymentDescriptor> cdd = new ArrayList<ChannelDeploymentDescriptor>( eg.getNumberOfEdges()); final int numberOfInputChannels = eg.getNumberOfEdges(); for (int j = 0; j < numberOfInputChannels; ++j) { final ExecutionEdge ee = eg.getEdge(j); cdd.add(new ChannelDeploymentDescriptor(ee.getOutputChannelID(), ee.getInputChannelID())); } igd.add(new GateDeploymentDescriptor(eg.getGateID(), eg.getChannelType(), cdd)); } final TaskDeploymentDescriptor tdd = new TaskDeploymentDescriptor(this.executionGraph.getJobID(), this.vertexID, this.groupVertex.getName(), this.indexInVertexGroup, this.groupVertex.getCurrentNumberOfGroupMembers(), this.executionGraph.getJobConfiguration(), this.groupVertex.getConfiguration(), this.groupVertex.getInvokableClass(), ogd, igd); return tdd; } }