Package org.apache.flink.runtime.taskmanager

Source Code of org.apache.flink.runtime.taskmanager.Task

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.flink.runtime.taskmanager;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.flink.configuration.Configuration;
import org.apache.flink.runtime.execution.ExecutionListener;
import org.apache.flink.runtime.execution.ExecutionState;
import org.apache.flink.runtime.execution.RuntimeEnvironment;
import org.apache.flink.runtime.executiongraph.ExecutionAttemptID;
import org.apache.flink.runtime.jobgraph.JobID;
import org.apache.flink.runtime.jobgraph.JobVertexID;
import org.apache.flink.runtime.memorymanager.MemoryManager;
import org.apache.flink.runtime.profiling.TaskManagerProfiler;
import org.apache.flink.util.ExceptionUtils;

public final class Task {

  /** For atomic state updates */
  private static final AtomicReferenceFieldUpdater<Task, ExecutionState> STATE_UPDATER =
      AtomicReferenceFieldUpdater.newUpdater(Task.class, ExecutionState.class, "executionState");
     
  /** The log object used for debugging. */
  private static final Logger LOG = LoggerFactory.getLogger(Task.class);

  // --------------------------------------------------------------------------------------------
 
  private final JobID jobId;
 
  private final JobVertexID vertexId;
 
  private final int subtaskIndex;
 
  private final int numberOfSubtasks;
 
  private final ExecutionAttemptID executionId;
 
  private final String taskName;

  private final TaskManager taskManager;
 
 
  private final List<ExecutionListener> executionListeners = new CopyOnWriteArrayList<ExecutionListener>();

  /** The environment (with the invokable) executed by this task */
  private volatile RuntimeEnvironment environment;
 
  /** The current execution state of the task */
  private volatile ExecutionState executionState = ExecutionState.DEPLOYING;

  // -------------------------------------------------------------------------------------------- 
 
  public Task(JobID jobId, JobVertexID vertexId, int taskIndex, int parallelism,
      ExecutionAttemptID executionId, String taskName, TaskManager taskManager)
  {
    this.jobId = jobId;
    this.vertexId = vertexId;
    this.subtaskIndex = taskIndex;
    this.numberOfSubtasks = parallelism;
    this.executionId = executionId;
    this.taskName = taskName;
    this.taskManager = taskManager;
  }


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

  /**
   * Returns the ID of this task vertex.
   *
   * @return the ID of this task vertex.
   */
  public JobVertexID getVertexID() {
    return this.vertexId;
  }

  /**
   * Gets the index of the parallel subtask [0, parallelism).
   *
   * @return The task index of the parallel subtask.
   */
  public int getSubtaskIndex() {
    return subtaskIndex;
  }
 
  /**
   * Gets the total number of subtasks of the task that this subtask belongs to.
   *
   * @return The total number of this task's subtasks.
   */
  public int getNumberOfSubtasks() {
    return numberOfSubtasks;
  }
 
  /**
   * Gets the ID of the execution attempt.
   *
   * @return The ID of the execution attempt.
   */
  public ExecutionAttemptID getExecutionId() {
    return executionId;
  }
 
  /**
   * Returns the current execution state of the task.
   *
   * @return the current execution state of the task
   */
  public ExecutionState getExecutionState() {
    return this.executionState;
  }
 
  public void setEnvironment(RuntimeEnvironment environment) {
    this.environment = environment;
  }
 
  public RuntimeEnvironment getEnvironment() {
    return environment;
  }
 
  public boolean isCanceledOrFailed() {
    return executionState == ExecutionState.CANCELING ||
        executionState == ExecutionState.CANCELED ||
        executionState == ExecutionState.FAILED;
  }
 
  public String getTaskName() {
    return taskName;
  }
 
  public String getTaskNameWithSubtasks() {
    return this.taskName + " (" + (this.subtaskIndex + 1) + "/" + this.numberOfSubtasks + ")";
  }
 
  // ----------------------------------------------------------------------------------------------------------------
  //  States and Transitions
  // ----------------------------------------------------------------------------------------------------------------
 
  /**
   * Marks the task as finished. This succeeds, if the task was previously in the state
   * "RUNNING", otherwise it fails. Failure indicates that the task was either
   * canceled, or set to failed.
   *
   * @return True, if the task correctly enters the state FINISHED.
   */
  public boolean markAsFinished() {
    if (STATE_UPDATER.compareAndSet(this, ExecutionState.RUNNING, ExecutionState.FINISHED)) {
      notifyObservers(ExecutionState.FINISHED, null);
      taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.FINISHED, null);
      return true;
    } else {
      return false;
    }
  }
 
  public void markFailed(Throwable error) {
    while (true) {
      ExecutionState current = this.executionState;
     
      // if canceled, fine. we are done, and the jobmanager has been told
      if (current == ExecutionState.CANCELED) {
        return;
      }
     
      // if canceling, we are done, but we cannot be sure that the jobmanager has been told.
      // after all, we may have recognized our failure state before the cancelling and never sent a canceled
      // message back
      else if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.FAILED)) {
        notifyObservers(ExecutionState.FAILED, ExceptionUtils.stringifyException(error));
        taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.FAILED, error);
        return;
      }
    }
  }
 
  public void cancelExecution() {
    while (true) {
      ExecutionState current = this.executionState;
     
      // if the task is already canceled (or canceling) or finished or failed,
      // then we need not do anything
      if (current == ExecutionState.FINISHED || current == ExecutionState.CANCELED ||
          current == ExecutionState.CANCELING || current == ExecutionState.FAILED)
      {
        return;
      }
     
      if (current == ExecutionState.DEPLOYING) {
        // directly set to canceled
        if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.CANCELED)) {
         
          notifyObservers(ExecutionState.CANCELED, null);
          taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.CANCELED, null);
          return;
        }
      }
      else if (current == ExecutionState.RUNNING) {
        // go to canceling and perform the actual task canceling
        if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.CANCELING)) {
         
          notifyObservers(ExecutionState.CANCELING, null);
          try {
            this.environment.cancelExecution();
          } catch (Throwable e) {
            LOG.error("Error while cancelling the task.", e);
          }
         
          return;
        }
      }
      else {
        throw new RuntimeException("unexpected state for cancelling: " + current);
      }
    }
  }
 
  /**
   * Sets the tasks to be cancelled and reports a failure back to the master.
   * This method is important if a failure needs to be reported to the master, because
   * a simple canceled m
   *
   * @param cause The exception to report in the error message
   */
  public void failExternally(Throwable cause) {
    while (true) {
      ExecutionState current = this.executionState;
     
      // if the task is already canceled (or canceling) or finished or failed,
      // then we need not do anything
      if (current == ExecutionState.FINISHED || current == ExecutionState.CANCELED ||
          current == ExecutionState.CANCELING || current == ExecutionState.FAILED)
      {
        return;
      }
     
      if (current == ExecutionState.DEPLOYING) {
        // directly set to canceled
        if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.FAILED)) {
         
          notifyObservers(ExecutionState.FAILED, null);
          taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.FAILED, cause);
          return;
        }
      }
      else if (current == ExecutionState.RUNNING) {
        // go to canceling and perform the actual task canceling
        if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.FAILED)) {
          try {
            this.environment.cancelExecution();
          } catch (Throwable e) {
            LOG.error("Error while cancelling the task.", e);
          }
         
          notifyObservers(ExecutionState.FAILED, null);
          taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.FAILED, cause);
         
          return;
        }
      }
      else {
        throw new RuntimeException("unexpected state for cancelling: " + current);
      }
    }
  }
 
  public void cancelingDone() {
    while (true) {
      ExecutionState current = this.executionState;
     
      if (current == ExecutionState.CANCELED || current == ExecutionState.FAILED) {
        return;
      }
      if (!(current == ExecutionState.RUNNING || current == ExecutionState.CANCELING)) {
        LOG.error(String.format("Unexpected state transition in Task: %s -> %s", current, ExecutionState.CANCELED));
      }
     
      if (STATE_UPDATER.compareAndSet(this, current, ExecutionState.CANCELED)) {
        notifyObservers(ExecutionState.CANCELED, null);
        taskManager.notifyExecutionStateChange(jobId, executionId, ExecutionState.CANCELED, null);
        return;
      }
    }
  }

  /**
   * Starts the execution of this task.
   */
  public boolean startExecution() {
    if (STATE_UPDATER.compareAndSet(this, ExecutionState.DEPLOYING, ExecutionState.RUNNING)) {
      final Thread thread = this.environment.getExecutingThread();
      thread.start();
      return true;
    } else {
      return false;
    }
  }
 
  /**
   * Unregisters the task from the central memory manager.
   *
   * @param memoryManager
   *        the central memory manager
   */
  public void unregisterMemoryManager(MemoryManager memoryManager) {
    RuntimeEnvironment env = this.environment;
    if (memoryManager != null && env != null) {
      memoryManager.releaseAll(env.getInvokable());
    }
  }
 
  // -----------------------------------------------------------------------------------------------------------------
  //                                        Task Profiling
  // -----------------------------------------------------------------------------------------------------------------

  /**
   * 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(TaskManagerProfiler taskManagerProfiler, Configuration jobConfiguration) {
    taskManagerProfiler.registerExecutionListener(this, jobConfiguration);
  }

  /**
   * Unregisters the task from the task manager profiler.
   *
   * @param taskManagerProfiler
   *        the task manager profiler
   */
  public void unregisterProfiler(TaskManagerProfiler taskManagerProfiler) {
    if (taskManagerProfiler != null) {
      taskManagerProfiler.unregisterExecutionListener(this.executionId);
    }
  }
 
  // --------------------------------------------------------------------------------------------
  //                                     State Listeners
  // --------------------------------------------------------------------------------------------
 
  public void registerExecutionListener(ExecutionListener listener) {
    if (listener == null) {
      throw new IllegalArgumentException();
    }
    this.executionListeners.add(listener);
  }

  public void unregisterExecutionListener(ExecutionListener listener) {
    if (listener == null) {
      throw new IllegalArgumentException();
    }
    this.executionListeners.remove(listener);
  }
 
  private void notifyObservers(ExecutionState newState, String message) {
    if (LOG.isInfoEnabled()) {
      LOG.info(getTaskNameWithSubtasks() + " switched to " + newState + (message == null ? "" : " : " + message));
    }
   
    for (ExecutionListener listener : this.executionListeners) {
      try {
        listener.executionStateChanged(jobId, vertexId, subtaskIndex, executionId, newState, message);
      }
      catch (Throwable t) {
        LOG.error("Error while calling execution listener.", t);
      }
    }
  }
 
  // --------------------------------------------------------------------------------------------
  //                                       Utilities
  // --------------------------------------------------------------------------------------------
 
  @Override
  public String toString() {
    return getTaskNameWithSubtasks() + " [" + executionState + ']';
  }
}
TOP

Related Classes of org.apache.flink.runtime.taskmanager.Task

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.