001    /*
002     * Queue.java
003     *
004     * Created on July 2, 2004, 7:37 PM
005     *
006     * This file is part of the STAR Scheduler.
007     * Copyright (c) 2002-2006 STAR Collaboration - Brookhaven National Laboratory
008     *
009     * STAR Scheduler is free software; you can redistribute it and/or modify
010     * it under the terms of the GNU General Public License as published by
011     * the Free Software Foundation; either version 2 of the License, or
012     * (at your option) any later version.
013     *
014     * STAR Scheduler is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017     * GNU General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with STAR Scheduler; if not, write to the Free Software
021     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022     */
023    
024    package gov.bnl.star.offline.scheduler;
025    
026    import gov.bnl.star.offline.scheduler.BatchSystem;
027    import gov.bnl.star.offline.scheduler.Dispatchers.QueueDiscriptorBase;
028    import gov.bnl.star.offline.scheduler.request.Request;
029    import gov.bnl.star.offline.scheduler.util.RDLApplicationResolver;
030    import gov.bnl.star.offline.scheduler.util.ConfigToolkit;
031    import gov.bnl.star.offline.scheduler.AccessMethod;
032    import gov.bnl.star.offline.scheduler.LocalAccessPoint;
033    
034    import java.util.ArrayList;
035    
036    import java.util.List;
037    
038    /** Description of a batch system queue.
039     *  @author  Levente Hajdu
040     */
041    public class Queue {
042        
043        /** Creates a new instance of Queue */
044        public Queue() {}
045        
046        private String Site;
047        private String QueueName ="No Name";
048        private String Cluster;
049        private int TimeLimit = -1; //the max time limit in min a jobs can run for inside this queue
050        private int maxMemory = -1; //The max ram a job a use before it is killed, if it runs in this queue
051        private int maxFiles = -1;
052        private int searchOrderPriority = 1;
053        private boolean Local = false;
054        private String ID = "No ID";
055        private String Type ="?";
056        private String Messages = "No Message";
057       // private Dispatcher dispatcher; // The dispatcher associated with this queue when submitting localy.
058       // private Dispatcher gridDispatcher; //The dispatcher associated with this queue when submitting between sites.
059        
060        private BatchSystem batchSystem;
061        
062        
063        List accessMethods = new ArrayList();
064        /**Return the list of all access methods under which this is queue is listed in the config **/
065        public List getAccessMethods(){ return accessMethods; }
066        /**Resets the accessMethods list for this queue.
067         * Note: This member should only be called by the framwork, when resubmitting jobs**/
068        public void setAccessMethods(List accessMethods){ this.accessMethods = accessMethods; }
069        /**Used by the framwork to configure the queue**/
070        public void addAccessMethod(AccessMethod accessMethod){ 
071            
072            this.accessMethods.add(accessMethod); 
073            //System.out.println(this.ID + " ---> " + accessMethods.size() + " ---> " + accessMethod.getAccessPoints().size()  );
074               
075        }
076        
077    
078        List QueueDiscriptors = new ArrayList();
079        /** Used to add a new QueueDiscriptor to relate the queue to a dispatcher. 
080          * The parameters this member takes are the same as the constructor for the gov.bnl.star.offline.scheduler.Dispatcher.QueueDiscriptor  class.    
081          * For more information see:  gov.bnl.star.offline.scheduler.Dispatcher.QueueDiscriptor    
082         **/
083        public void addQueueDiscriptors(QueueDiscriptorBase queueDiscriptor){
084            QueueDiscriptors.add(queueDiscriptor);     
085        }
086        public List getQueueDiscriptors(){return QueueDiscriptors;}
087        public void setQueueDiscriptors(){this.QueueDiscriptors = QueueDiscriptors;}
088        
089        
090        private String Implementation = "local"; //all queues are local by default
091        
092        private String rejectIfTargetHostStartsWith; 
093        private RDLApplicationResolver RDLApp; //Used to resolve rdl apps, basical it fills in the command area of the job.
094        
095        
096        public double baseResponseTime; //This memebers is used only by  ML pol
097        public int Ncpus; //This memebers is used only by  ML pol
098        public double accumulatedResponseTime = 0; //This memebers is used only by  ML pol
099        
100        //public List hosts; //this data will be gotten from a command line thread.
101        
102        public void setRDLApplicationResolver(RDLApplicationResolver RDLApp){this.RDLApp = RDLApp;}
103        public RDLApplicationResolver getRDLApplicationResolver(){return RDLApp;}    
104             
105        public String getRejectIfTargetHostStartsWith(){
106            return rejectIfTargetHostStartsWith;
107        }
108        
109        public void setRejectIfTargetHostStartsWith(String RejectIfTargetHostStartsWith){
110            this.rejectIfTargetHostStartsWith = RejectIfTargetHostStartsWith; 
111        }
112        
113        /** Is it a "local" queue, "grid" queue, or another type of queue */
114        public String getImplementation(){
115            return Implementation;
116        }
117        
118        /** This string is "local" by default is can also be "grid" or other */
119        public void setImplementation(String Implementation){
120            this.Implementation = Implementation;
121        }
122        
123        
124        /// Sets the queue as a local queue
125        public void setOptimizeAsLocalQueue(){
126            Local = true;
127        }
128        
129        /** Returns true is this is a local queue */
130        public boolean IsOptimizedAsLocalQueue(){
131            return Local; 
132        }
133        
134        /**
135         *Returns information about why jobs do / don't fit after calling the doesJobFit()
136         */ 
137        public String getMessages(){
138            return Messages;
139        }
140        
141        public void setSite(String Site){
142            this.Site = Site;
143        }
144        
145        public String getSite(){
146            return Site;
147        }
148        
149        
150        /** Sets a name used by the, Cluster Dispatcher Chooser to send the job to the right queue
151         * This value should be set in the config file
152         *@param Cluster associatedDispatcher The name in the CompositeDispatchers table
153         */
154        public void setCluster(String Cluster){
155            this.Cluster = Cluster;
156        }
157        
158        /** Returns the cluster name of the cluster the queue is on
159         *
160        */
161        public String getCluster(){
162            return Cluster;
163        }
164        
165        
166        //This is uesed inpart to get the ML name, it should be changed so that the ML name can be typed Drectly
167        public void setType(String Type){
168              this.Type = Type.trim();
169        }
170        
171        //This is uesed inpart to get the ML name, it should be changed so that the ML name can be typed Drectly
172        public String getType(){
173              return Type;
174        }
175       
176        /**Becuase not all queues have names an ID  is used.
177         * Sets the ID of the queue, this value is only used for the report file
178         * Note: All queues in the config file should -aways- be given an ID.
179         */
180        public void setID(String QueueID){
181              this.ID = QueueID.trim();
182        }
183        
184        /**Becuase not all queues have names an ID  is used, in case data about the queue must be printed. 
185           Note: All queues in the config file should -aways- be given an ID.**/
186        public String getID(){
187              return ID;
188        }
189        
190        
191        /** Sets the name of the queue, used by LSF and other dispatchers
192         */
193        public void setName(String QueueName){
194              this.QueueName = QueueName.trim();
195        }
196        
197        /** Returns the name of the Queue
198         * @return Name of the queue
199         *
200         */
201        public String getName(){
202              return QueueName;
203        }
204        
205     
206        
207        
208        
209        
210        /*This function returns the access method  for this queue. Note that it must always return the same access method
211         *becuase it can be called more then once for the same job.
212         *
213         *If the queue is note local the first agatekeeper access method will be returned, else if it can't find any it will
214         *fail and halt. If the job is local will return the first local access method it finds. If no local access method can
215         *is found it will returne the first grid access method. If no grid access method is found it will halt. 
216         */
217        /*
218        public AccessMethod getAssociatedAccessMethod(){
219    
220               
221            if(ConfigToolkit.getToolkit().isLocalQueue(this)){
222                    for(int i = 0; i != this.accessMethods.size(); i++){  
223                        AccessMethod accessMethod = (AccessMethod) this.accessMethods.get(i);
224                        if( ((LocalAccessPoint) accessMethod.getAccessPoints().get(0)).isLocal() ){ //It is assumed that if one accessPoint is local all accessPoints associated with that point will be local. 
225                            return accessMethod;
226                        }
227                    } 
228                    System.out.println("could not find local access point for " + this.ID + " looking for grid gatekeeper access point.");
229             } 
230              
231             
232            
233            for(int i = 0; i != this.accessMethods.size(); i++){  
234                AccessMethod accessMethod = (AccessMethod) this.accessMethods.get(i);
235                
236                //for(int z = 0; z != accessMethod.getAccessPoints().size(); z++  )
237                //       System.out.println( "\n" + accessMethod.getAccessPoints().get(z).getClass().toString() + "---------------->" + z + "------------------>" + accessMethod.getAccessPoints().get(z).getClass().isInstance(new GateKeeperAccessPoint()) );
238                
239                if(! ( (LocalAccessPoint) accessMethod.getAccessPoints().get(0) ).isLocal() ){  //It is assumed that if one accessPoint is local all accessPoints associated with that point will be local. 
240                    return accessMethod;
241                }
242                
243            }
244            throw new RuntimeException("No Grid accessMethod could be found for the queue: " + this.ID + "\nThis may be becuase the policy you are using was not intended to be run from this site or it may be a misconfiguration.");
245              
246    
247        }
248        */
249        
250        
251    
252        /**Recovers the dispatcher to be used by this queue from the config**/
253        
254    //    public Dispatcher getAssociatedDispatcher(){
255    //            
256    //          if(ConfigToolkit.getToolkit().isLocalQueue(this)){
257    //            return this.batchSystem.getLocalDispatcher();
258    //          } 
259    //          else{
260    //            return this.batchSystem.getGridDispatcher();
261    //          }
262    //        
263    //       
264    //        
265    //          //return this.getAssociatedAccessMethod().getDispatcher();
266    //        
267    //    }
268    
269        
270        //This function is called by the batch system tag when a queue is added. There is 
271        public void setBatchSystem(BatchSystem batchSystem){
272           // if(batchSystem == null) System.out.println("The value is null debug -3865923");
273            if(this.batchSystem != null) System.out.println("Warring!!! The batch for the queue \"" + this.ID + "\" has already been set to \"" + this.batchSystem.getName() + "\" and is now being reset to \"" + batchSystem.getName() + "\".  Remember this object can not be referenced with idref�s in more then one batch tag. Please check the config file.");
274            this.batchSystem = batchSystem;
275        }
276    
277    /*    
278        public BatchSystem getBatchSystem(){
279            System.out.println("--------------getting batch system -----------------");
280            return batchSystem;
281        }
282    */    
283        
284        
285        /** The name (may be NULL) of the associated dispatcher. The string may be used for routing by some CompositeDispatchers 
286         * This value should be set in the config file
287         */
288    //    public String getAssociatedDispatcher(){ //deprecated 
289    //          return associatedDispatcher;
290     //   }
291       
292        /** Sets the time limit(in minutes) a job can stay in the queue before it gets killed.
293          * This value should be set in the config file
294          * A lower number may be use then the max true queue make time limit for tweaking.
295          *
296          *@param TimeLimit Time in minutes
297          */
298        public void setTimeLimit(int TimeLimit){
299            this.TimeLimit = TimeLimit;
300            //System.out.println("setTimeLimit called, TimeLimit = " + TimeLimit);
301        }
302        
303        /** The time limit(in minutes) a job can stay in the queue before it gets killed or before it needs to find an other queue.
304          */
305        public int getTimeLimit(){
306            return TimeLimit;
307        }
308    
309        /** This is the max memeory (ram) in MB a job will use before it is killed.  
310          * If you know what your doing you can make the number smaller, to change the way it behaves.
311          * This value should be set in the config file
312          */
313        public void setMaxMemory(int maxMemory){
314            this.maxMemory = maxMemory;
315        }
316        
317        /** The max memory a job may have in order for it to be assined to this queue. */ 
318        public int getMaxMemory(){
319            return maxMemory;
320        }
321        
322        
323        public void setSearchOrderPriority(int searchOrderPriority){
324            this.searchOrderPriority = searchOrderPriority;
325        }
326        
327       /** The Search Order Priority number of the queue
328        *@return the Search Order Priority number of the queue*/
329        public int getSearchOrderPriority(){
330            return searchOrderPriority;
331        }
332        
333        /** Test if this queue meets the hard unchangable limits (jobTimeLimit and memlimit) of the queue
334          *  @return True if job fits
335         */
336        public boolean doesJobFit(Job job, Request request){
337            
338            //If the rejectIfTargetHostStartsWith string is set and if the target host of the job starts with the same staring, reject the job
339            if((rejectIfTargetHostStartsWith != null) && (job.getTarget() != null)){
340                if(job.getTarget().startsWith(rejectIfTargetHostStartsWith)){
341                    Messages = job.getJobID() + " rejected from " + getName() + " becasue job target starts with \"" + rejectIfTargetHostStartsWith +"\"."; 
342                    return false;
343                }   
344            }
345                    
346            //does the MaxMemory rec. match
347            if((job.getMaxMemory() > getMaxMemory())&&(!(getMaxMemory() == -1))){
348                Messages = job.getJobID() + " did not fit in " + getName() + " queueMaxMemory = " + getMaxMemory() + "MB Job is asking for " + job.getMaxMemory() + "MB"; 
349                return false;
350            }
351            
352            if((job.getMinMemory() > getMaxMemory())&&(!(getMaxMemory() == -1))){
353                Messages = job.getJobID() + " did not fit in " + getName() + " queueMaxMemory = " + getMaxMemory() + "MB Job is asking for " + job.getMinMemory() + "MB"; 
354                return  false;
355            }
356            
357            //does the time rec. match
358            if(request.getFilesPerHour() == -1){
359                Messages = job.getJobID() + " fit in " + getName(); 
360                return true; //if the job has to time stated
361            }
362            
363            double jobTimeLimit = (((double) job.getInput().size()) / request.getFilesPerHour()) * 60; //how long a job will take one job to run in min
364          
365            if((job.getInput().size() == 0)&&(request.getFilesPerHour() != Double.POSITIVE_INFINITY)){
366                jobTimeLimit = 60 / request.getFilesPerHour(); //If the job has a FilesPerHour but no file, then the FilesPerHour is the time the job takes
367            }
368    
369            if((jobTimeLimit > this.getTimeLimit())&&(request.getFilesPerHour() != Double.POSITIVE_INFINITY) && (TimeLimit != -1)){
370                Messages = job.getJobID() + " did not fit in " + getName() + " Queue time limit = " + this.getTimeLimit() + "min job estimated run time : " + jobTimeLimit + "min = (" + job.getInput().size() + "files/" + request.getFilesPerHour() + "FilesPerHour*60)" ; 
371                return  false;
372                //System.out.println("No fit of "+ getName() +" on " + job.getJobID()  +" Timelimmit, job time lim / queue time lim = " + jobTimeLimit + " / " + TimeLimit);
373            }
374            
375            //System.out.println("Good fit of "+ getName() +" on " + job.getJobID());
376            Messages = job.getJobID() + " fit in " + getName(); 
377            return true;
378        }
379        
380        
381        /** Returns true if some jobs this request may fit inside the queue. Returns flase if jobs from this request could never be able to fit this queue.
382         */
383        public boolean willJobsFit(Request request){
384            boolean jobfits = true;
385            
386            //does the MaxMemory rec. match
387            if ((request.getResource("Memory").getMax() > getMaxMemory())
388                &&(!(getMaxMemory() == -1))) {
389                jobfits = false;
390                //System.out.println("No fit of "+ getName() +" on " + job.getJobID()  +" QueueMaxmem = " + getMaxMemory() + "JobsMaxmem = " + job.getMaxMemory());
391            }
392            
393            if ((request.getResource("Memory").getMin() > getMaxMemory())
394                &&(!(getMaxMemory() == -1))) {
395                jobfits = false;
396                //System.out.println("No fit of "+ getName() +" on " + job.getJobID()  +" Minmem");
397            }
398            
399             return jobfits;
400        }
401        
402        String remoteGateway = "remoteGatewayNotSet";
403        String localGateway = "localGatewayNotSet";
404        public String getRemoteGateway(){return remoteGateway;}
405        public void setRemoteGateway(String remoteGateway){this.remoteGateway = remoteGateway;}
406        public String getLocalGateway(){return localGateway;}
407        public void setLocalGateway(String localGateway){this.localGateway = localGateway;}
408        
409        
410        
411        
412        
413      
414    }