/**
* Copyright 2007-2015 University Of Southern California
*
* 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 edu.isi.pegasus.planner.refiner.cleanup.constraint;
import edu.isi.pegasus.common.logging.LogManager;
import edu.isi.pegasus.planner.classes.Job;
import edu.isi.pegasus.planner.classes.PegasusFile;
import edu.isi.pegasus.planner.partitioner.graph.Graph;
import edu.isi.pegasus.planner.partitioner.graph.GraphNode;
import org.supercsv.cellprocessor.ParseLong;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.prefs.CsvPreference;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
/**
*
* @author Sudarshan Srinivasan
* @author Rafael Ferreira da Silva
*/
public class Utilities {
// Default file size of 10 MB
private static final long DEFAULT_FILE_SIZE = 10485760;
//Maps from file name to file size
static Map<String, Long> sizes = null;
public static long getFileSize(PegasusFile file) {
if (sizes == null || sizes.get(file.getLFN()) == null) {
long fileSize = (long) file.getSize();
return fileSize == -1 ? DEFAULT_FILE_SIZE : fileSize;
}
return sizes.get(file.getLFN());
}
public static String cleanUpJobToString(Iterable<GraphNode> parents, Iterable<GraphNode> heads, Iterable<PegasusFile> listOfFiles) {
StringBuilder sb = new StringBuilder("CleanupJob{parents = {");
for (GraphNode parent : parents) {
sb.append(parent.getID());
sb.append(',');
}
sb.replace(sb.length() - 1, sb.length(), "}, children = {");
for (GraphNode child : heads) {
sb.append(child.getID());
sb.append(',');
}
sb.replace(sb.length() - 1, sb.length(), "}, files = {");
for (PegasusFile file : listOfFiles) {
sb
.append(file.getLFN())
.append(':')
.append(getFileSize(file))
.append(',');
}
sb.replace(sb.length() - 1, sb.length(), "}}");
return sb.toString();
}
/**
* Read file sizes from CSV file.
*
* @param csvName CSV file name.
* @throws IOException
*/
public static void loadHashMap(String csvName) throws IOException {
final CellProcessor[] processors = new CellProcessor[]{null, null, null, null, new ParseLong()};
CsvBeanReader beanReader = new CsvBeanReader(new FileReader(csvName), CsvPreference.STANDARD_PREFERENCE);
final String[] header = beanReader.getHeader(true);
FileDataBean fileDataBean;
sizes = new HashMap<String, Long>();
while ((fileDataBean = beanReader.read(FileDataBean.class, header, processors)) != null) {
Long currentSize = sizes.get(fileDataBean.filename);
if (currentSize != null) {
assert (fileDataBean.length == currentSize);
}
sizes.put(fileDataBean.filename, fileDataBean.length);
}
}
/**
*
* @param workflow
* @param mLogger
* @return
*/
public static Map<GraphNode, Set<GraphNode>> calculateDependencies(Graph workflow, LogManager mLogger) {
//Dependencies is used to map from node to its dependencies
Map<GraphNode, Set<GraphNode>> dependencies = new HashMap<GraphNode, Set<GraphNode>>();
//This is our BFS queue
LinkedList<GraphNode> bfsQueue = new LinkedList<GraphNode>();
//This is a marker node used to indicate an increase in depth while exploring
final GraphNode marker = new GraphNode("Marker");
//Initially, add all root nodes to the BFS queue
for (GraphNode currentRoot : workflow.getRoots()) {
bfsQueue.addLast(currentRoot);
}
try {
outer:
while (true) {
//Remove one node from the BFS queue
GraphNode currentNode = bfsQueue.removeFirst();
//Ensure that the removed node is not already explored
if (dependencies.containsKey(currentNode)) {
continue;
}
//Move past any marker nodes we see
while (currentNode == marker) {
currentNode = bfsQueue.removeFirst();
}
mLogger.log("Pre analysis of node " + currentNode.getID(), LogManager.DEBUG_MESSAGE_LEVEL);
//Initialise the dependency set for the current node
Set<GraphNode> currentNodeDependencies = new HashSet<GraphNode>();
//Iterate over all the parent nodes
for (GraphNode parent : currentNode.getParents()) {
//Ensure that we've already calculated dependencies for this parent node
//Otherwise we could end up in trouble here
if (!dependencies.containsKey(parent)) {
//if we've not yet calculated dependencies for even one of the parents
//then push this node sufficiently back in the queue
//that we would have calculated all parent dependencies when we return
//Basically, push the node to the start of the next level
ListIterator<GraphNode> iterator = bfsQueue.listIterator();
for (GraphNode searchElement = iterator.next(); iterator.hasNext(); searchElement = iterator.next()) {
if (searchElement == marker) {
iterator.add(currentNode);
break;
}
}
continue outer;
}
//Update the current node's dependencies
currentNodeDependencies.add(parent);
currentNodeDependencies.addAll(dependencies.get(parent));
}
//Add the current node to the dependencies table
dependencies.put(currentNode, currentNodeDependencies);
//Add a marker followed by this node's children
bfsQueue.add(marker);
bfsQueue.addAll(currentNode.getChildren());
}
} catch (NoSuchElementException e) {
}
return dependencies;
}
public static long getIntermediateRequirement(Job currentJob) {
long spaceUsed = 0;
switch (currentJob.getJobType()) {
case Job.CLEANUP_JOB:
for (PegasusFile currentFile : (Set<PegasusFile>) currentJob.getInputFiles()) {
spaceUsed -= getFileSize(currentFile);
}
break;
case Job.STAGE_OUT_JOB:
return 0;
default:
for (PegasusFile currentFile : (Set<PegasusFile>) currentJob.getOutputFiles()) {
spaceUsed += getFileSize(currentFile);
}
}
return spaceUsed;
}
}