/***********************************************************************************************************************
* 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;
}
}