/** * Copyright 2007-2008 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.partitioner; import edu.isi.pegasus.common.logging.LoggingKeys; import edu.isi.pegasus.common.logging.LogManager; import org.griphyn.vdl.classes.LFN; import org.griphyn.vdl.dax.ADAG; import org.griphyn.vdl.dax.Filename; import org.griphyn.vdl.dax.Job; import org.griphyn.vdl.euryale.Callback; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * This class ends up writing a partitioned dax, that corresponds to one * partition as defined by the Partitioner. It looks up the dax once when * it is initialized, stores it in memory and then refers the memory to look * up the job details for the jobs making up a particular partition. * * @author Karan Vahi * @version $Revision$ */ public class SingleLook extends DAXWriter{ /** * The set of job id's in the partition. */ private Set mNodeSet; /** * A map containing the relations between the jobs making up the partition. */ private Map mRelationsMap; /** * The ADAG object containing the partitioned dax. */ private ADAG mPartADAG; /** * The number of jobs that are in the partition. */ private int mNumOfJobs; /** * The number of jobs about which the callback interface has knowledge. */ private int mCurrentNum; /** * The flag to identify that dax is in memory. */ private boolean mDAXInMemory; /** * The map containing all the jobs in the dax indexed by the job id. */ private Map mJobMap; /** * The overloaded constructor. * * @param daxFile the path to the dax file that is being partitioned. * @param directory the directory in which the partitioned daxes are to be * generated. */ public SingleLook(String daxFile, String directory){ super(daxFile,directory); mDAXInMemory = false; mJobMap = null; } /** * It writes out a dax consisting of the jobs as specified in the partition. * * @param partition the partition object containing the relations and id's * of the jobs making up the partition. * @param index the index of the partition. * * @return boolean true if dax successfully generated and written. * false in case of error. */ public boolean writePartitionDax(Partition partition, int index){ Iterator it; List fileList = null; List parentIDs = null; //do the cleanup from the previous partition write mPartADAG = null; mNodeSet = null; mRelationsMap = null; //get from the partition object the set of jobs //and relations between them mNodeSet = partition.getNodeIDs(); mRelationsMap = partition.getRelations(); mNumOfJobs = mNodeSet.size(); //set the current number of jobs whose information we have mCurrentNum = 0; if(!mDAXInMemory){ mLogger.logEventStart( LoggingKeys.EVENT_PEGASUS_PARSE_DAX, LoggingKeys.DAX_ID, mDaxFile ); //dax is not in memory. mJobMap = new java.util.HashMap(); //Callback takes care of putting dax in memory Callback callback = new MyCallBackHandler(); org.griphyn.vdl.euryale.DAXParser d = new org.griphyn.vdl.euryale.DAXParser(null); d.setCallback(callback); //start the parsing of the dax d.parse(mDaxFile); mDAXInMemory = true; mLogger.logEventCompletion(); } mPartADAG = new ADAG(0,index,mPartitionName); //get the job information for the jobs in the partiton. it = mNodeSet.iterator(); while(it.hasNext()){ String id = (String)it.next(); Job job = (Job)mJobMap.get(id); if(job == null){ throw new RuntimeException( "Unable to find information about job" + id + "while constructing partition" ); } //add the job to ADAG mPartADAG.addJob(job); //build up the files used by the partition fileList = job.getUsesList(); //iterate through the file list //populate it in the ADAG object Iterator fileIt = fileList.iterator(); while(fileIt.hasNext()){ Filename file = (Filename)fileIt.next(); mPartADAG.addFilename(file.getFilename(), (file.getLink() == LFN.INPUT)?true:false, file.getTemporary(), file.getDontRegister(),file.getDontTransfer()); } } //put in the relations amongst //jobs in the partition //add the relations between the jobs in the partition to the ADAG it = mRelationsMap.keySet().iterator(); while(it.hasNext()){ String childID = (String)it.next(); parentIDs = (List)mRelationsMap.get(childID); //get all the parents of the children and populate them in the //ADAG object Iterator it1 = parentIDs.iterator(); while(it1.hasNext()){ mPartADAG.addChild(childID,(String)it1.next()); } } mLogger.log("Writing out the DAX File for partition " + partition.getID(), LogManager.DEBUG_MESSAGE_LEVEL); //do the actual writing to the file this.initializeWriteHandle(index); try{ mPartADAG.toXML(mWriteHandle, ""); } catch(IOException e){ mLogger.log("Error while writing out a partition dax :" + e.getMessage(),LogManager.ERROR_MESSAGE_LEVEL); return false; } this.close(); mLogger.log("Writing out the DAX File for partition - DONE" + partition.getID(), LogManager.DEBUG_MESSAGE_LEVEL); //generation was successful return true; } /** * The internal callback handler for the DAXParser in Euryale. It stores * all the jobs making up the dax in an internal map, which is then referred * to get the job information for the jobs making up the partition. */ private class MyCallBackHandler implements Callback { /** * The empty constructor. */ public MyCallBackHandler(){ } /** * Callback when the opening tag was parsed. The attribute maps each * attribute to its raw value. The callback initializes the DAG * writer. * * @param attributes is a map of attribute key to attribute value */ public void cb_document(Map attributes) { //do nothing at the moment } /** * Callback for the filename from section 1 filenames. * Does nothing as the filenames for the partitioned dax are * constructed from the jobs. */ public void cb_filename(Filename filename) { //an empty implementation } /** * Callback for the job from section 2 jobs. This ends up storing all * the jobs in the memory to be used for writing out the partition dax. * * @param job the object containing the job information. */ public void cb_job(Job job) { String id = job.getID(); //put it in hashmap and also check for duplicate if(mJobMap.put(id,job) != null){ //warn for the duplicate entry mLogger.log("Entry for the job already in ", LogManager.WARNING_MESSAGE_LEVEL); } if(mCurrentNum == mNumOfJobs){ //exit or stop the parser. cb_done(); } } /** * Callback for child and parent relationships from section 3. * This is an empty implementation, as the Partition object * contains the relations amongst the jobs making up the partition. * * @param child is the IDREF of the child element. * @param parents is a list of IDREFs of the included parents. */ public void cb_parents(String child, List parents) { //an empty implementation } /** * Callback when the parsing of the document is done. While this state * could also be determined from the return of the invocation of the * parser, that return may be hidden in another place of the code. * This callback can be used to free callback-specific resources. */ public void cb_done(){ //an empty implementation } } }