/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.utils.cluster.torque.internal;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.rcenvironment.core.utils.cluster.ClusterJobInformation;
import de.rcenvironment.core.utils.cluster.ClusterJobInformation.ClusterJobState;
import de.rcenvironment.core.utils.cluster.ClusterService;
import de.rcenvironment.core.utils.cluster.internal.AbstractClusterService;
import de.rcenvironment.core.utils.cluster.internal.ClusterJobInformationImpl;
import de.rcenvironment.core.utils.cluster.internal.ClusterJobTimesInformation;
import de.rcenvironment.core.utils.ssh.jsch.SshSessionConfiguration;
/**
* TORQUE implementation of {@link ClusterService}.
* @author Doreen Seider
*/
public class TorqueClusterService extends AbstractClusterService {
private static final int INDEX_JOBID = 0;
private static final int INDEX_USER = 1;
private static final int INDEX_QUEUE = 2;
private static final int INDEX_JOBNAME = 3;
private static final int INDEX_JOBSTATE = 9;
private static final int INDEX_REMAININGTIME = 4;
private static final int INDEX_STARTTIME = 5;
private static final int INDEX_QUEUETIME = 5;
private static final int SECTION_ACTIVE_JOBS = 0;
private static final int SECTION_IDLE_JOBS = 1;
private static final int SECTION_BLOCKED_JOBS = 2;
// only for OSGi
@Deprecated
public TorqueClusterService() {}
public TorqueClusterService(SshSessionConfiguration sshConfiguration, Map<String, String> pathToQueuingSystemCommands) {
super(sshConfiguration, pathToQueuingSystemCommands);
}
@Override
protected Set<ClusterJobInformation> fetchAndParseClusterJobInformation() throws IOException {
String stdout = executesCommand(jschSession, buildMainCommand("qstat") + " -a", REMOTE_WORK_DIR);
Map<String, ClusterJobInformation> jobInformation = parseStdoutForClusterJobInformation(stdout);
latestFetchedJobInformation = Collections.unmodifiableMap(jobInformation);
latestFetch = new Date().getTime();
stdout = executesCommand(jschSession, buildMainCommand("showq"), REMOTE_WORK_DIR);
Map<String, ClusterJobTimesInformation> jobTimesInformation = parseStdoutForClusterJobTimesInformation(stdout);
return enhanceClusterJobInformation(jobInformation, jobTimesInformation);
}
@Override
public String cancelClusterJobs(List<String> jobIds) throws IOException {
StringBuilder commandBuilder = new StringBuilder(buildMainCommand("qdel") + " ");
for (String jobId : jobIds) {
commandBuilder.append(" ");
commandBuilder.append(jobId);
}
try {
executesCommand(jschSession, commandBuilder.toString(), REMOTE_WORK_DIR);
} catch (IllegalArgumentException e) {
return e.getMessage();
}
return "";
}
// visibility is protected for test purposes
protected Map<String, ClusterJobInformation> parseStdoutForClusterJobInformation(String stdout) {
Map<String, ClusterJobInformation> jobInformation = new HashMap<String, ClusterJobInformation>();
final String regex = "(-+)";
boolean headerCompleted = false;
boolean isHeader = false;
String[] lines = stdout.split("\n");
for (String line : lines) {
headerCompleted = isHeader;
String[] lineTokens = line.split("(\\s+)");
if (headerCompleted) {
ClusterJobInformation information = extractClusterJobInformation(lineTokens);
jobInformation.put(information.getJobId(), information);
} else {
isHeader = true;
for (String attribute : lineTokens) {
if (!attribute.matches(regex)) {
isHeader = false;
break;
}
}
}
}
return jobInformation;
}
// visibility is protected for test purposes
protected Map<String, ClusterJobTimesInformation> parseStdoutForClusterJobTimesInformation(String stdout) {
Map<String, ClusterJobTimesInformation> information = new HashMap<String, ClusterJobTimesInformation>();
int section = SECTION_ACTIVE_JOBS;
boolean inSection = false;
boolean emptyRowPassed = false;
String[] lines = stdout.split("\n");
for (String line : lines) {
String[] lineTokens = line.split("(\\s+)");
if (inSection) {
if (lineTokens.length <= 1) {
if (!emptyRowPassed) {
emptyRowPassed = true;
} else {
emptyRowPassed = false;
inSection = false;
section++;
}
} else {
ClusterJobTimesInformation timesInformation = extractClusterJobTimesInformation(lineTokens, section);
information.put(timesInformation.getJobId(), timesInformation);
}
} else {
for (String attribute : lineTokens) {
if (attribute.matches("JOBNAME")) {
inSection = true;
break;
}
}
}
}
return information;
}
// visibility is protected for test purposes
protected Set<ClusterJobInformation> enhanceClusterJobInformation(Map<String, ClusterJobInformation> jobInformation,
Map<String, ClusterJobTimesInformation> jobTimesInformation) {
jobInformation = enhanceClusterJobInformationWithTimesInformation(jobInformation, jobTimesInformation);
return new HashSet<ClusterJobInformation>(jobInformation.values());
}
private Map<String, ClusterJobInformation> enhanceClusterJobInformationWithTimesInformation(
Map<String, ClusterJobInformation> jobInformation, Map<String, ClusterJobTimesInformation> jobTimesInformation) {
for (ClusterJobInformation information : jobInformation.values()) {
String jobName = information.getJobId().split("\\.")[0];
if (jobTimesInformation.containsKey(jobName)) {
((ClusterJobInformationImpl) information).setClusterJobTimesInformation(jobTimesInformation.get(jobName));
} else {
((ClusterJobInformationImpl) information).setClusterJobTimesInformation(new ClusterJobTimesInformation());
}
}
return jobInformation;
}
private ClusterJobTimesInformation extractClusterJobTimesInformation(String[] lineTokens, int section) {
ClusterJobTimesInformation information = new ClusterJobTimesInformation();
information.setJobId(lineTokens[INDEX_JOBID]);
switch (section) {
case SECTION_ACTIVE_JOBS:
information.setRemainingTime(lineTokens[INDEX_REMAININGTIME]);
information.setStartTime(getTime(lineTokens, INDEX_STARTTIME));
break;
case SECTION_IDLE_JOBS:
case SECTION_BLOCKED_JOBS:
default:
information.setQueueTime(getTime(lineTokens, INDEX_QUEUETIME));
break;
}
return information;
}
private String getTime(String[] lineTokens, int startIndex) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = startIndex; i < lineTokens.length; i++) {
stringBuffer.append(lineTokens[i]);
stringBuffer.append(" ");
}
return stringBuffer.delete(stringBuffer.length() - 1, stringBuffer.length()).toString();
}
private ClusterJobInformation extractClusterJobInformation(String[] lineTokens) {
ClusterJobInformationImpl information = new ClusterJobInformationImpl();
information.setJobId(lineTokens[INDEX_JOBID]);
information.setUser(lineTokens[INDEX_USER]);
information.setQueue(lineTokens[INDEX_QUEUE]);
information.setJobName(lineTokens[INDEX_JOBNAME]);
information.setJobState(getClusterJobState(lineTokens[INDEX_JOBSTATE]));
return information;
}
private ClusterJobState getClusterJobState(String stateToken) {
ClusterJobState state = ClusterJobState.Unknown;
if (stateToken.equals("C")) {
state = ClusterJobState.Completed;
} else if (stateToken.equals("E")) {
state = ClusterJobState.Exiting;
} else if (stateToken.equals("H")) {
state = ClusterJobState.Held;
} else if (stateToken.equals("Q")) {
state = ClusterJobState.Queued;
} else if (stateToken.equals("R")) {
state = ClusterJobState.Running;
} else if (stateToken.equals("T")) {
state = ClusterJobState.Moved;
} else if (stateToken.equals("W")) {
state = ClusterJobState.Waiting;
} else if (stateToken.equals("S")) {
state = ClusterJobState.Suspended;
}
return state;
}
}