eu.stratosphere.nephele.taskmanager.Task.java Source code

Java tutorial

Introduction

Here is the source code for eu.stratosphere.nephele.taskmanager.Task.java

Source

/***********************************************************************************************************************
 * 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.taskmanager;

import eu.stratosphere.configuration.Configuration;
import eu.stratosphere.nephele.execution.Environment;
import eu.stratosphere.nephele.execution.ExecutionListener;
import eu.stratosphere.nephele.execution.ExecutionObserver;
import eu.stratosphere.nephele.execution.ExecutionState;
import eu.stratosphere.nephele.execution.ExecutionStateTransition;
import eu.stratosphere.nephele.execution.RuntimeEnvironment;
import eu.stratosphere.nephele.executiongraph.ExecutionVertexID;
import eu.stratosphere.nephele.jobgraph.JobID;
import eu.stratosphere.nephele.profiling.TaskManagerProfiler;
import eu.stratosphere.nephele.services.memorymanager.MemoryManager;
import eu.stratosphere.nephele.template.AbstractInvokable;
import eu.stratosphere.util.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public final class Task implements ExecutionObserver {

    /**
     * The log object used for debugging.
     */
    private static final Log LOG = LogFactory.getLog(Task.class);

    private final ExecutionVertexID vertexID;

    private final RuntimeEnvironment environment;

    private final TaskManager taskManager;

    /**
     * Stores whether the task has been canceled.
     */
    private volatile boolean isCanceled = false;

    /**
     * The current execution state of the task
     */
    private volatile ExecutionState executionState = ExecutionState.STARTING;

    private Queue<ExecutionListener> registeredListeners = new ConcurrentLinkedQueue<ExecutionListener>();

    public Task(ExecutionVertexID vertexID, final RuntimeEnvironment environment, TaskManager taskManager) {
        this.vertexID = vertexID;
        this.environment = environment;
        this.taskManager = taskManager;

        this.environment.setExecutionObserver(this);
    }

    /**
     * Returns the ID of the job this task belongs to.
     * 
     * @return the ID of the job this task belongs to
     */
    public JobID getJobID() {
        return this.environment.getJobID();
    }

    /**
     * Returns the ID of this task.
     * 
     * @return the ID of this task
     */
    public ExecutionVertexID getVertexID() {
        return this.vertexID;
    }

    /**
     * Returns the environment associated with this task.
     * 
     * @return the environment associated with this task
     */
    public Environment getEnvironment() {
        return this.environment;
    }

    /**
     * Marks the task as failed and triggers the appropriate state changes.
     */
    public void markAsFailed() {
        executionStateChanged(ExecutionState.FAILED, "Execution thread died unexpectedly");
    }

    public void cancelExecution() {
        cancelOrKillExecution(true);
    }

    public void killExecution() {
        cancelOrKillExecution(false);
    }

    /**
     * Cancels or kills the task.
     *
     * @param cancel <code>true/code> if the task shall be canceled, <code>false</code> if it shall be killed
     */
    private void cancelOrKillExecution(boolean cancel) {
        final Thread executingThread = this.environment.getExecutingThread();

        if (executingThread == null) {
            return;
        }

        if (this.executionState != ExecutionState.RUNNING && this.executionState != ExecutionState.FINISHING) {
            return;
        }

        LOG.info((cancel ? "Canceling " : "Killing ") + this.environment.getTaskNameWithIndex());

        if (cancel) {
            this.isCanceled = true;
            // Change state
            executionStateChanged(ExecutionState.CANCELING, null);

            // Request user code to shut down
            try {
                final AbstractInvokable invokable = this.environment.getInvokable();
                if (invokable != null) {
                    invokable.cancel();
                }
            } catch (Throwable e) {
                LOG.error(StringUtils.stringifyException(e));
            }
        }

        // Continuously interrupt the user thread until it changed to state CANCELED
        while (true) {

            executingThread.interrupt();

            if (!executingThread.isAlive()) {
                break;
            }

            try {
                executingThread.join(1000);
            } catch (InterruptedException e) {
            }

            if (!executingThread.isAlive()) {
                break;
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("Sending repeated " + (cancel == true ? "canceling" : "killing") + " signal to "
                        + this.environment.getTaskName() + " with state " + this.executionState);
            }
        }
    }

    /**
     * Checks if the state of the thread which is associated with this task is <code>TERMINATED</code>.
     * 
     * @return <code>true</code> if the state of this thread which is associated with this task is
     *         <code>TERMINATED</code>, <code>false</code> otherwise
     */
    public boolean isTerminated() {
        final Thread executingThread = this.environment.getExecutingThread();
        if (executingThread.getState() == Thread.State.TERMINATED) {
            return true;
        }

        return false;
    }

    /**
     * Starts the execution of this task.
     */
    public void startExecution() {

        final Thread thread = this.environment.getExecutingThread();
        thread.start();
    }

    /**
     * Registers the task manager profiler with the task.
     * 
     * @param taskManagerProfiler
     *        the task manager profiler
     * @param jobConfiguration
     *        the configuration attached to the job
     */
    public void registerProfiler(final TaskManagerProfiler taskManagerProfiler,
            final Configuration jobConfiguration) {
        taskManagerProfiler.registerExecutionListener(this, jobConfiguration);
    }

    /**
     * Unregisters the task from the central memory manager.
     * 
     * @param memoryManager
     *        the central memory manager
     */
    public void unregisterMemoryManager(final MemoryManager memoryManager) {
        if (memoryManager != null) {
            memoryManager.releaseAll(this.environment.getInvokable());
        }
    }

    /**
     * Unregisters the task from the task manager profiler.
     * 
     * @param taskManagerProfiler
     *        the task manager profiler
     */
    public void unregisterProfiler(final TaskManagerProfiler taskManagerProfiler) {
        if (taskManagerProfiler != null) {
            taskManagerProfiler.unregisterExecutionListener(this.vertexID);
        }
    }

    /**
     * Returns the current execution state of the task.
     * 
     * @return the current execution state of the task
     */
    public ExecutionState getExecutionState() {
        return this.executionState;
    }

    // -----------------------------------------------------------------------------------------------------------------
    //                                        ExecutionObserver methods
    // -----------------------------------------------------------------------------------------------------------------
    @Override
    public void executionStateChanged(final ExecutionState newExecutionState, final String optionalMessage) {

        // Check the state transition
        ExecutionStateTransition.checkTransition(false, getTaskName(), this.executionState, newExecutionState);

        // Make sure the reason for a transition to FAILED appears in the log files
        if (newExecutionState == ExecutionState.FAILED) {
            LOG.error(optionalMessage);
        }

        // Notify all listener objects
        final Iterator<ExecutionListener> it = this.registeredListeners.iterator();
        while (it.hasNext()) {
            it.next().executionStateChanged(this.environment.getJobID(), this.vertexID, newExecutionState,
                    optionalMessage);
        }

        // Store the new execution state
        this.executionState = newExecutionState;

        // Finally propagate the state change to the job manager
        this.taskManager.executionStateChanged(this.environment.getJobID(), this.vertexID, newExecutionState,
                optionalMessage);
    }

    /**
     * Returns the name of the task associated with this observer object.
     *
     * @return the name of the task associated with this observer object
     */
    private String getTaskName() {

        return this.environment.getTaskName() + " (" + (this.environment.getIndexInSubtaskGroup() + 1) + "/"
                + this.environment.getCurrentNumberOfSubtasks() + ")";
    }

    @Override
    public void userThreadStarted(final Thread userThread) {

        // Notify the listeners
        final Iterator<ExecutionListener> it = this.registeredListeners.iterator();
        while (it.hasNext()) {
            it.next().userThreadStarted(this.environment.getJobID(), this.vertexID, userThread);
        }
    }

    @Override
    public void userThreadFinished(final Thread userThread) {

        // Notify the listeners
        final Iterator<ExecutionListener> it = this.registeredListeners.iterator();
        while (it.hasNext()) {
            it.next().userThreadFinished(this.environment.getJobID(), this.vertexID, userThread);
        }
    }

    /**
     * Registers the {@link ExecutionListener} object for this task. This object
     * will be notified about important events during the task execution.
     *
     * @param executionListener
     *        the object to be notified for important events during the task execution
     */

    public void registerExecutionListener(final ExecutionListener executionListener) {

        this.registeredListeners.add(executionListener);
    }

    /**
     * Unregisters the {@link ExecutionListener} object for this environment. This object
     * will no longer be notified about important events during the task execution.
     *
     * @param executionListener
     *        the lister object to be unregistered
     */

    public void unregisterExecutionListener(final ExecutionListener executionListener) {

        this.registeredListeners.remove(executionListener);
    }

    @Override
    public boolean isCanceled() {

        return this.isCanceled;
    }

    /**
     * Returns the runtime environment associated with this task.
     *
     * @return the runtime environment associated with this task
     */
    public RuntimeEnvironment getRuntimeEnvironment() {

        return this.environment;
    }
}