org.ow2.proactive.scheduler.core.TerminationData.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive.scheduler.core.TerminationData.java

Source

/*
 * ProActive Parallel Suite(TM):
 * The Open Source library for parallel and distributed
 * Workflows & Scheduling, Orchestration, Cloud Automation
 * and Big Data Analysis on Enterprise Grids & Clouds.
 *
 * Copyright (c) 2007 - 2017 ActiveEon
 * Contact: contact@activeeon.com
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation: version 3 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 */
package org.ow2.proactive.scheduler.core;

import static org.ow2.proactive.scheduler.core.TerminationData.TerminationStatus.ABORTED;
import static org.ow2.proactive.scheduler.core.TerminationData.TerminationStatus.NODEFAILED;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.collections4.ListUtils;
import org.apache.log4j.Logger;
import org.ow2.proactive.scheduler.common.job.JobId;
import org.ow2.proactive.scheduler.common.job.JobVariable;
import org.ow2.proactive.scheduler.common.task.TaskId;
import org.ow2.proactive.scheduler.common.task.TaskResult;
import org.ow2.proactive.scheduler.common.task.TaskVariable;
import org.ow2.proactive.scheduler.common.task.util.SerializationUtil;
import org.ow2.proactive.scheduler.core.properties.PASchedulerProperties;
import org.ow2.proactive.scheduler.core.rmproxies.RMProxiesManager;
import org.ow2.proactive.scheduler.job.InternalJob;
import org.ow2.proactive.scheduler.synchronization.SynchronizationWrapper;
import org.ow2.proactive.scheduler.task.SchedulerVars;
import org.ow2.proactive.scheduler.task.TaskResultImpl;
import org.ow2.proactive.scheduler.task.internal.InternalTask;
import org.ow2.proactive.scheduler.task.internal.InternalTaskParentFinder;
import org.ow2.proactive.scheduler.task.utils.VariablesMap;
import org.ow2.proactive.utils.TaskIdWrapper;

/*
 * Keeps information about actions which should be executed when task/job
 * terminates.
 */
final class TerminationData {

    public static final Logger logger = Logger.getLogger(SchedulingService.class);

    static class TaskTerminationData {

        private final RunningTaskData taskData;

        private final TaskResultImpl taskResult;

        private final InternalJob internalJob;

        private final TerminationStatus terminationStatus;

        TaskTerminationData(InternalJob internalJob, RunningTaskData taskData, TerminationStatus terminationStatus,
                TaskResultImpl taskResult) {
            this.taskData = taskData;
            this.terminationStatus = terminationStatus;
            this.taskResult = taskResult;
            this.internalJob = internalJob;
        }

        public boolean terminatedWhileRunning() {
            return taskData.getLauncher() != null;
        }

    }

    public enum TerminationStatus {
        NORMAL, ABORTED, NODEFAILED
    }

    static class TaskRestartData {

        private final TaskId taskId;

        private final long waitTime;

        TaskRestartData(TaskId taskId, long waitTime) {
            this.taskId = taskId;
            this.waitTime = waitTime;
        }

    }

    private final Set<JobId> jobsToTerminate;

    private final Map<TaskIdWrapper, TaskTerminationData> tasksToTerminate;

    private final Map<TaskIdWrapper, TaskRestartData> tasksToRestart;

    private final InternalTaskParentFinder internalTaskParentFinder;

    static final TerminationData EMPTY = new TerminationData(Collections.emptySet(), Collections.emptyMap(),
            Collections.emptyMap());

    static TerminationData newTerminationData() {
        return new TerminationData(new HashSet<>(), new HashMap<>(), new HashMap<>());
    }

    private TerminationData(Set<JobId> jobsToTerminate, Map<TaskIdWrapper, TaskTerminationData> tasksToTerminate,
            Map<TaskIdWrapper, TaskRestartData> tasksToRestart) {
        this.jobsToTerminate = jobsToTerminate;
        this.tasksToTerminate = tasksToTerminate;
        this.tasksToRestart = tasksToRestart;
        this.internalTaskParentFinder = InternalTaskParentFinder.getInstance();
    }

    void addJobToTerminate(JobId jobId) {
        jobsToTerminate.add(jobId);
    }

    void addTaskData(InternalJob jobData, RunningTaskData taskData, TerminationStatus terminationStatus,
            TaskResultImpl taskResult) {
        tasksToTerminate.put(TaskIdWrapper.wrap(taskData.getTask().getId()),
                new TaskTerminationData(jobData, taskData, terminationStatus, taskResult));
    }

    void addRestartData(TaskId taskId, long waitTime) {
        tasksToRestart.put(TaskIdWrapper.wrap(taskId), new TaskRestartData(taskId, waitTime));
    }

    boolean isEmpty() {
        return tasksToTerminate.isEmpty() && tasksToRestart.isEmpty() && jobsToTerminate.isEmpty();
    }

    boolean jobTerminated(JobId jobId) {
        return jobsToTerminate.contains(jobId);
    }

    boolean taskTerminated(JobId j, String taskName) {
        for (TaskIdWrapper taskIdWrapper : tasksToTerminate.keySet()) {
            if (taskIdWrapper.getTaskId().getReadableName().equals(taskName)) {
                return true;
            }
        }
        return false;
    }

    void handleTermination(final SchedulingService service) throws IOException, ClassNotFoundException {

        terminateTasks(service);

        restartWaitingTasks(service);

        terminateJobs(service);
    }

    private void terminateJobs(final SchedulingService service) {
        for (JobId jobId : jobsToTerminate) {
            service.terminateJobHandling(jobId);
        }
    }

    private void restartWaitingTasks(final SchedulingService service) {
        for (final TaskRestartData restartData : tasksToRestart.values()) {
            service.getInfrastructure().schedule(() -> service.getJobs().restartWaitingTask(restartData.taskId),
                    restartData.waitTime);
        }
    }

    private void terminateTasks(final SchedulingService service) {

        if (tasksToTerminate.values().isEmpty()) {
            return;
        }

        ExecutorService parallelTerminationService = Executors.newFixedThreadPool(tasksToTerminate.values().size());

        try {
            List<Callable<Void>> callables = new ArrayList<>(tasksToTerminate.values().size());

            for (final TaskTerminationData taskToTerminate : tasksToTerminate.values()) {

                callables.add(() -> {
                    try {
                        RunningTaskData taskData = taskToTerminate.taskData;
                        if (taskToTerminate.terminatedWhileRunning()) {
                            terminateRunningTask(service, taskToTerminate, taskData);
                        }
                    } catch (Throwable e) {
                        logger.error("Failed to terminate task " + taskToTerminate.taskData.getTask().getName(), e);
                        throw new RuntimeException(e);
                    }
                    return null;
                });
            }
            parallelTerminationService.invokeAll(callables);
        } catch (Exception e) {
            logger.error("Failed to terminate tasks ", e);
        } finally {
            parallelTerminationService.shutdown();
        }
    }

    private void terminateRunningTask(SchedulingService service, TaskTerminationData taskToTerminate,
            RunningTaskData taskData) {
        Map<String, String> genericInformation = new HashMap<>();
        VariablesMap variables = null;
        if (taskToTerminate.internalJob != null) {
            genericInformation = taskData.getTask().getRuntimeGenericInformation();
        }
        try {
            variables = getStringSerializableMap(service, taskToTerminate);
        } catch (Exception e) {
            logger.error("Exception occurred, fail to get variables into the cleaning script: ", e);
        }
        try {
            if (taskToTerminate.terminationStatus == ABORTED) {
                taskData.getLauncher().kill();
            }
        } catch (Throwable t) {
            logger.info("Cannot terminate task launcher for task '" + taskData.getTask().getId() + "'", t);
            try {
                logger.info("Task launcher that cannot be terminated is identified by "
                        + taskData.getLauncher().toString());
            } catch (Throwable ignore) {
                logger.info("Getting information about Task launcher failed (remote object not accessible?)");
            }
        }

        try {
            logger.debug("Releasing nodes for task '" + taskData.getTask().getId() + "'");
            RMProxiesManager proxiesManager = service.getInfrastructure().getRMProxiesManager();
            proxiesManager.getUserRMProxy(taskData.getUser(), taskData.getCredentials()).releaseNodes(
                    taskData.getNodes(),
                    taskToTerminate.terminationStatus != NODEFAILED ? taskData.getTask().getCleaningScript() : null,
                    variables, genericInformation, taskToTerminate.taskData.getTask().getId(),
                    service.addThirdPartyCredentials(taskData.getCredentials()),
                    new SynchronizationWrapper(taskToTerminate.internalJob.getOwner(), taskData.getTask().getId(),
                            taskToTerminate.internalJob.getSynchronizationAPI()));

        } catch (Throwable t) {
            logger.info("Failed to release nodes for task '" + taskData.getTask().getId() + "'", t);
        }
    }

    public VariablesMap getStringSerializableMap(SchedulingService service, TaskTerminationData taskToTerminate)
            throws Exception {
        VariablesMap variablesMap = new VariablesMap();

        RunningTaskData taskData = taskToTerminate.taskData;
        TaskResultImpl taskResult = taskToTerminate.taskResult;
        InternalJob internalJob = taskToTerminate.internalJob;

        if (taskToTerminate.terminationStatus == ABORTED || taskResult == null) {
            List<InternalTask> iDependences = taskData.getTask().getIDependences();
            if (iDependences != null) {
                Set<TaskId> parentIds = new HashSet<>(iDependences.size());
                for (InternalTask parentTask : iDependences) {
                    parentIds.addAll(
                            InternalTaskParentFinder.getInstance().getFirstNotSkippedParentTaskIds(parentTask));
                }

                // Batch fetching of parent tasks results
                Map<TaskId, TaskResult> taskResults = new HashMap<>();
                for (List<TaskId> parentsSubList : ListUtils.partition(new ArrayList<>(parentIds),
                        PASchedulerProperties.SCHEDULER_DB_FETCH_TASK_RESULTS_BATCH_SIZE.getValueAsInt())) {
                    taskResults.putAll(service.getInfrastructure().getDBManager()
                            .loadTasksResults(taskData.getTask().getJobId(), parentsSubList));
                }
                getResultsFromListOfTaskResults(variablesMap.getInheritedMap(), taskResults);
            } else {
                if (internalJob != null) {
                    for (Map.Entry<String, JobVariable> jobVariableEntry : internalJob.getVariables().entrySet()) {
                        variablesMap.getInheritedMap().put(jobVariableEntry.getKey(),
                                jobVariableEntry.getValue().getValue());
                    }
                }
            }
            variablesMap.getInheritedMap().put(SchedulerVars.PA_TASK_SUCCESS.toString(), Boolean.toString(false));
        } else if (taskResult.hadException()) {
            variablesMap.setInheritedMap(fillMapWithTaskResult(taskResult, false));

        } else {
            variablesMap.setInheritedMap(fillMapWithTaskResult(taskResult, true));
        }
        variablesMap.setScopeMap(getNonInheritedScopeVariables(variablesMap.getInheritedMap(),
                taskData.getTask().getScopeVariables(), taskData.getTask().getVariables()));
        return variablesMap;
    }

    private Map<String, Serializable> getNonInheritedScopeVariables(Map<String, Serializable> inheritedVariables,
            Map<String, Serializable> scopeVariables, Map<String, TaskVariable> taskVariables) {
        Map<String, Serializable> scopeMap = new HashMap<>();
        for (Map.Entry<String, Serializable> entry : scopeVariables.entrySet()) {
            if (!taskVariables.get(entry.getKey()).isJobInherited()
                    || (taskVariables.get(entry.getKey()).isJobInherited()
                            && !inheritedVariables.containsKey(entry.getKey()))) {
                scopeMap.put(entry.getKey(), entry.getValue());
            }
        }
        return scopeMap;
    }

    private Map<String, Serializable> fillMapWithTaskResult(TaskResultImpl taskResult, boolean normalTermination)
            throws IOException, ClassNotFoundException {
        Map<String, Serializable> variables;
        variables = SerializationUtil.deserializeVariableMap(taskResult.getPropagatedVariables());
        variables.put(SchedulerVars.PA_TASK_SUCCESS.toString(), Boolean.toString(normalTermination));
        return variables;
    }

    private void getResultsFromListOfTaskResults(Map<String, Serializable> variables,
            Map<TaskId, TaskResult> taskResults) throws IOException, ClassNotFoundException {
        for (TaskResult currentTaskResult : taskResults.values()) {
            if (currentTaskResult.getPropagatedVariables() != null) {
                variables.putAll(
                        SerializationUtil.deserializeVariableMap(currentTaskResult.getPropagatedVariables()));
            }
        }
    }
}