~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/libs/sched/sge_select_queue.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*___INFO__MARK_BEGIN__*/
 
2
/*************************************************************************
 
3
 * 
 
4
 *  The Contents of this file are made available subject to the terms of
 
5
 *  the Sun Industry Standards Source License Version 1.2
 
6
 * 
 
7
 *  Sun Microsystems Inc., March, 2001
 
8
 * 
 
9
 * 
 
10
 *  Sun Industry Standards Source License Version 1.2
 
11
 *  =================================================
 
12
 *  The contents of this file are subject to the Sun Industry Standards
 
13
 *  Source License Version 1.2 (the "License"); You may not use this file
 
14
 *  except in compliance with the License. You may obtain a copy of the
 
15
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 
16
 * 
 
17
 *  Software provided under this License is provided on an "AS IS" basis,
 
18
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 
19
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 
20
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 
21
 *  See the License for the specific provisions governing your rights and
 
22
 *  obligations concerning the Software.
 
23
 * 
 
24
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
25
 * 
 
26
 *   Copyright: 2001 by Sun Microsystems, Inc.
 
27
 * 
 
28
 *   All Rights Reserved.
 
29
 * 
 
30
 ************************************************************************/
 
31
/*___INFO__MARK_END__*/
 
32
#include <stdio.h>
 
33
#include <string.h>
 
34
#include <stdlib.h>
 
35
#include <float.h>
 
36
#include <limits.h>
 
37
#ifdef SGE_PQS_API
 
38
#include <dlfcn.h>
 
39
#endif
 
40
 
 
41
#include "msg_common.h"
 
42
#include "basis_types.h"
 
43
#include "sge.h"
 
44
#include "sgermon.h"
 
45
#include "sge_log.h"
 
46
#include "cull.h"
 
47
#include "sge_select_queue.h"
 
48
#include "sge_select_queueL.h"
 
49
#include "sge_parse_num_par.h"
 
50
#include "sge_complex_schedd.h"
 
51
#include "valid_queue_user.h"
 
52
#include "subordinate_schedd.h"
 
53
#include "sge_range_schedd.h"
 
54
#include "sge_pe_schedd.h"
 
55
#include "sge_range.h"
 
56
#include "sge_qeti.h"
 
57
 
 
58
#include "sge_orderL.h"
 
59
#include "sge_pe.h"
 
60
#include "sge_ctL.h"
 
61
#include "sge_qinstanceL.h"
 
62
#include "sge_strL.h"
 
63
#ifdef SGE_PQS_API
 
64
#include "sge_varL.h"
 
65
#endif
 
66
#include "sort_hosts.h"
 
67
#include "schedd_monitor.h"
 
68
#include "schedd_message.h"
 
69
#include "msg_schedd.h"
 
70
#include "sge_schedd_text.h"
 
71
#include "sge_ja_task.h"
 
72
#include "sge_string.h"
 
73
#include "sge_hostname.h"
 
74
#include "sge_host.h"
 
75
#include "sge_job.h"
 
76
#include "sge_cqueue.h"
 
77
#include "sge_qinstance.h"
 
78
#include "sge_qinstance_type.h"
 
79
#include "sge_userprj.h"
 
80
#include "sge_ckpt.h"
 
81
#include "sge_centry.h"
 
82
#include "sge_object.h"
 
83
#include "sge_resource_utilization.h"
 
84
#include "sge_qinstance_state.h"
 
85
#include "sge_schedd_conf.h"
 
86
#include "sge_subordinate.h"
 
87
#include "sge_qref.h"
 
88
#ifdef SGE_PQS_API
 
89
#include "sge_pqs_api.h"
 
90
#endif
 
91
#include "sge_calendarL.h"
 
92
#include "sge_attrL.h"
 
93
#include "sched/sge_resource_quota_schedd.h"
 
94
#include "sgeobj/sge_advance_reservation.h"
 
95
#include "sgeobj/sge_userset.h"
 
96
#include "sgeobj/sge_hgroup.h"
 
97
#include "uti/sge_time.h"
 
98
 
 
99
/* -- these implement helpers for the category optimization -------- */
 
100
 
 
101
typedef struct {
 
102
   lListElem *category;          /* ref to the category */
 
103
   lListElem *cache;             /* ref to the cache object in th category */
 
104
   bool       use_category;      /* if true: use the category 
 
105
                                    with immediate dispatch runs only and only if there is more than a single job of that category 
 
106
                                    prevents 'skip_host_list' and 'skip_queue_list' be used with reservation */
 
107
   bool       mod_category;      /* if true: update the category with new messages, queues, and hosts */
 
108
   u_long32  *posible_pe_slots;  /* stores all posible slots settings for a pe job with ranges */  
 
109
   bool      is_pe_slots_rev;    /* if it is true, the posible_pe_slots are stored in the category */
 
110
} category_use_t;
 
111
 
 
112
static void 
 
113
fill_category_use_t(const sge_assignment_t *best, category_use_t *use_category, const char *pe_name);
 
114
 
 
115
static bool
 
116
add_pe_slots_to_category(category_use_t *use_category, u_long32 *max_slotsp, lListElem *pe, 
 
117
                         int min_slots, int max_slots, lList *pe_range);
 
118
/* -- these implement parallel assignemnt ------------------------- */
 
119
 
 
120
static dispatch_t
 
121
parallel_reservation_max_time_slots(sge_assignment_t *best, int *available_slots);
 
122
 
 
123
static dispatch_t
 
124
parallel_maximize_slots_pe(sge_assignment_t *best, int *available_slots);
 
125
 
 
126
static dispatch_t 
 
127
parallel_assignment(sge_assignment_t *a, category_use_t *use_category, int *available_slots);
 
128
 
 
129
#ifdef SOLARIS
 
130
#pragma no_inline(parallel_assignment)
 
131
#endif
 
132
 
 
133
static dispatch_t 
 
134
parallel_available_slots(const sge_assignment_t *a, int *slots, int *slots_qend); 
 
135
 
 
136
static dispatch_t
 
137
parallel_tag_queues_suitable4job(sge_assignment_t *assignment, category_use_t *use_category, int *available_slots);
 
138
 
 
139
static dispatch_t 
 
140
parallel_global_slots(const sge_assignment_t *a, int *slots, int *slots_qend);
 
141
 
 
142
static dispatch_t
 
143
parallel_tag_hosts_queues(sge_assignment_t *a, lListElem *hep, int *slots, 
 
144
                   int *slots_qend, bool *master_host, category_use_t *use_category,
 
145
                   lList **unclear_cqueue_list);
 
146
 
 
147
#ifdef SOLARIS
 
148
#pragma no_inline(parallel_tag_hosts_queues)
 
149
#endif
 
150
 
 
151
static int 
 
152
parallel_max_host_slots(sge_assignment_t *a, lListElem *host);
 
153
 
 
154
 
 
155
static dispatch_t
 
156
parallel_queue_slots(sge_assignment_t *a,lListElem *qep, int *slots, int *slots_qend, 
 
157
                    bool allow_non_requestable);
 
158
 
 
159
static 
 
160
void clean_up_parallel_job(sge_assignment_t *a); 
 
161
 
 
162
/* -- these implement sequential assignemnt ---------------------- */
 
163
 
 
164
static dispatch_t
 
165
sequential_tag_queues_suitable4job(sge_assignment_t *a);
 
166
 
 
167
static dispatch_t
 
168
sequential_queue_time( u_long32 *start, const sge_assignment_t *a, int *violations, lListElem *qep); 
 
169
 
 
170
static dispatch_t
 
171
sequential_host_time(u_long32 *start, const sge_assignment_t *a, int *violations, lListElem *hep); 
 
172
 
 
173
static dispatch_t
 
174
sequential_global_time(u_long32 *start_time, const sge_assignment_t *a, int *violations); 
 
175
 
 
176
static dispatch_t
 
177
match_static_advance_reservation(const sge_assignment_t *a);
 
178
 
 
179
static int 
 
180
sequential_update_host_order(lList *host_list, lList *queues);
 
181
 
 
182
/* -- base functions ---------------------------------------------- */
 
183
 
 
184
static int 
 
185
compute_soft_violations(const sge_assignment_t *a, lListElem *queue, int violation, lList *load_attr, lList *config_attr,
 
186
                    lList *actual_attr, u_long32 layer, double lc_factor, u_long32 tag);
 
187
 
 
188
static dispatch_t 
 
189
rc_time_by_slots(const sge_assignment_t *a, lList *requested, lList *load_attr, lList *config_attr, lList *actual_attr, 
 
190
                 lListElem *queue, bool allow_non_requestable, dstring *reason, int slots,
 
191
                 u_long32 layer, double lc_factor, u_long32 tag, u_long32 *start_time, const char *object_name);
 
192
 
 
193
 
 
194
 
 
195
static dispatch_t
 
196
ri_slots_by_time(const sge_assignment_t *a, int *slots, int *slots_qend, 
 
197
                lList *rue_list, lListElem *request, lList *load_attr, lList *total_list, lListElem *queue, 
 
198
                u_long32 layer, double lc_factor, dstring *reason, bool allow_non_requestable, 
 
199
                bool no_centry, const char *object_name);
 
200
 
 
201
static dispatch_t
 
202
match_static_resource(int slots, lListElem *req_cplx, lListElem *src_cplx, dstring *reason, 
 
203
             int is_threshold, int force_existence, bool allow_non_requestable);
 
204
 
 
205
static int 
 
206
resource_cmp(u_long32 relop, double req, double src_dl); 
 
207
 
 
208
static bool 
 
209
job_is_forced_centry_missing(const lListElem *job, const lList *master_centry_list, const lListElem *queue_or_host);
 
210
 
 
211
static void 
 
212
clear_resource_tags( lList *resources, u_long32 max_tag); 
 
213
 
 
214
static dispatch_t 
 
215
find_best_result(dispatch_t r1, dispatch_t r2);
 
216
 
 
217
/* ---- helpers for load computation ---------------------------------------------------------- */
 
218
 
 
219
static lListElem
 
220
*load_locate_elem(lList *load_list, lListElem *global_consumable, lListElem *host_consumable, 
 
221
                  lListElem *queue_consumable, const char *limit); 
 
222
 
 
223
#ifdef SGE_PQS_API
 
224
static int
 
225
sge_call_pe_qsort(sge_assignment_t *a, const char *qsort_args);
 
226
#endif
 
227
 
 
228
static int 
 
229
load_check_alarm(char *reason, const char *name, const char *load_value, const char *limit_value, 
 
230
                     u_long32 relop, u_long32 type, lListElem *hep, lListElem *hlep, double lc_host, 
 
231
                     double lc_global, const lList *load_adjustments, int load_is_value); 
 
232
 
 
233
static int 
 
234
load_np_value_adjustment(const char* name, lListElem *hep, double *load_correction);
 
235
 
 
236
/* ---- Implementation ------------------------------------------------------------------------- */
 
237
 
 
238
void assignment_init(sge_assignment_t *a, lListElem *job, lListElem *ja_task, bool is_load_adj)
 
239
{
 
240
   if (job != NULL) {
 
241
      a->job         = job;
 
242
      a->user        = lGetString(job, JB_owner);
 
243
      a->group       = lGetString(job, JB_group);
 
244
      a->project     = lGetString(job, JB_project);
 
245
      a->job_id      = lGetUlong(job, JB_job_number);
 
246
      a->is_soft     = job_has_soft_requests(job);
 
247
   }
 
248
 
 
249
   if (is_load_adj) {
 
250
      a->load_adjustments = sconf_get_job_load_adjustments();
 
251
   }
 
252
   
 
253
   if (ja_task != NULL) {
 
254
      a->ja_task     = ja_task;
 
255
      a->ja_task_id  = lGetUlong(ja_task, JAT_task_number);
 
256
   }   
 
257
}
 
258
 
 
259
void assignment_copy(sge_assignment_t *dst, sge_assignment_t *src, bool move_gdil)
 
260
{
 
261
   if (dst == NULL || src == NULL) {
 
262
      return;
 
263
   }
 
264
 
 
265
   if (dst->load_adjustments != NULL) {
 
266
      lFreeList(&dst->load_adjustments);
 
267
   }
 
268
 
 
269
   if (move_gdil) {
 
270
      lFreeList(&(dst->gdil));
 
271
      lFreeList(&(dst->limit_list));
 
272
      lFreeList(&(dst->skip_cqueue_list));
 
273
      lFreeList(&(dst->skip_host_list));
 
274
   }
 
275
 
 
276
   memcpy(dst, src, sizeof(sge_assignment_t));
 
277
 
 
278
   if (src->load_adjustments != NULL) {
 
279
      dst->load_adjustments = lCopyList("cpy_load_adj", src->load_adjustments);
 
280
   }
 
281
 
 
282
   if (!move_gdil)
 
283
      dst->gdil = dst->limit_list = dst->skip_cqueue_list = dst->skip_host_list = NULL; 
 
284
   else
 
285
      src->gdil = src->limit_list = src->skip_cqueue_list = src->skip_host_list = NULL; 
 
286
}
 
287
 
 
288
void assignment_release(sge_assignment_t *a)
 
289
{
 
290
   lFreeList(&(a->load_adjustments));
 
291
   lFreeList(&(a->gdil));
 
292
   lFreeList(&(a->limit_list));
 
293
   lFreeList(&(a->skip_cqueue_list));
 
294
   lFreeList(&(a->skip_host_list));
 
295
}
 
296
 
 
297
void assignment_clear_cache(sge_assignment_t *a)
 
298
{
 
299
   lFreeList(&(a->limit_list));
 
300
   lFreeList(&(a->skip_cqueue_list));
 
301
   lFreeList(&(a->skip_host_list));
 
302
}
 
303
 
 
304
static dispatch_t 
 
305
find_best_result(dispatch_t r1, dispatch_t r2)
 
306
{
 
307
   DENTER(BASIS_LAYER, "find_best_result");
 
308
 
 
309
   if (r1 == DISPATCH_NEVER || 
 
310
            r2 == DISPATCH_NEVER) {
 
311
      DRETURN(DISPATCH_NEVER);
 
312
   }
 
313
   else if (r1 == DISPATCH_OK || 
 
314
       r2 == DISPATCH_OK) {
 
315
      DRETURN(DISPATCH_OK);
 
316
   }   
 
317
   else if (r1 == DISPATCH_NOT_AT_TIME || 
 
318
            r2 == DISPATCH_NOT_AT_TIME) {
 
319
      DRETURN(DISPATCH_NOT_AT_TIME);
 
320
   }   
 
321
   else if (r1 == DISPATCH_NEVER_JOB || 
 
322
            r2 == DISPATCH_NEVER_JOB) {
 
323
      DRETURN(DISPATCH_NEVER_JOB);
 
324
   }
 
325
   else if (r1 ==  DISPATCH_NEVER_CAT ||
 
326
            r2 == DISPATCH_NEVER_CAT) {
 
327
      DRETURN(DISPATCH_NEVER_CAT);
 
328
   }
 
329
   else if (r1 == DISPATCH_MISSING_ATTR  ||
 
330
            r2 == DISPATCH_MISSING_ATTR ) {
 
331
      DRETURN(DISPATCH_MISSING_ATTR);
 
332
   }
 
333
 
 
334
   CRITICAL((SGE_EVENT, MSG_JOBMATCHINGUNEXPECTEDRESULT));
 
335
   DRETURN(DISPATCH_NEVER);
 
336
}
 
337
 
 
338
 
 
339
static bool 
 
340
is_not_better(sge_assignment_t *a, u_long32 viola_best, u_long32 tt_best, u_long32 viola_this, u_long32 tt_this) 
 
341
{
 
342
   /* earlier start time has higher preference than lower soft violations */
 
343
   if (a->is_reservation && tt_this >= tt_best)
 
344
      return true;
 
345
   if (!a->is_reservation && viola_this >= viola_best)
 
346
      return true;
 
347
   return false;
 
348
}
 
349
 
 
350
/****** scheduler/sge_select_parallel_environment() ****************************
 
351
*  NAME
 
352
*     sge_select_parallel_environment() -- Decide about a PE assignment 
 
353
*
 
354
*  SYNOPSIS
 
355
*     static dispatch_t sge_select_parallel_environment(sge_assignment_t *best, lList 
 
356
*     *pe_list) 
 
357
*
 
358
*  FUNCTION
 
359
*     When users use wildcard PE request such as -pe <pe_range> 'mpi8_*' 
 
360
*     more than a single parallel environment can match the wildcard expression. 
 
361
*     In case of 'now' assignments the PE that gives us the largest assignment 
 
362
*     is selected. When scheduling a reservation we search for the earliest 
 
363
*     assignment for each PE and then choose that one that finally gets us the 
 
364
*     maximum number of slots.
 
365
*
 
366
* IMPORTANT
 
367
*     The scheduler info messages are not cached. They are added globaly and have
 
368
*     to be added for each job in the category. When the messages are updated
 
369
*     this has to be changed.
 
370
*
 
371
*  INPUTS
 
372
*     sge_assignment_t *best - herein we keep all important in/out information
 
373
*     lList *pe_list         - the list of all parallel environments (PE_Type)
 
374
*
 
375
*  RESULT
 
376
*     dispatch_t - 0 ok got an assignment
 
377
*                  1 no assignment at the specified time (???)
 
378
*                 -1 assignment will never be possible for all jobs of that category
 
379
*                 -2 assignment will never be possible for that particular job
 
380
*
 
381
*  NOTES
 
382
*     MT-NOTE: sge_select_parallel_environment() is not MT safe 
 
383
*******************************************************************************/
 
384
dispatch_t
 
385
sge_select_parallel_environment(sge_assignment_t *best, lList *pe_list) 
 
386
{
 
387
   int matched_pe_count = 0;
 
388
   lListElem *pe;
 
389
   const char *pe_request, *pe_name;
 
390
   dispatch_t result, best_result = DISPATCH_NEVER_CAT;
 
391
   int old_logging = 0;
 
392
 
 
393
   DENTER(TOP_LAYER, "sge_select_parallel_environment");
 
394
 
 
395
   pe_request = lGetString(best->job, JB_pe);
 
396
 
 
397
   DPRINTF(("handling parallel job "sge_u32"."sge_u32"\n", best->job_id, best->ja_task_id)); 
 
398
 
 
399
   if (best->is_reservation) { /* reservation scheduling */
 
400
 
 
401
      if (!best->is_advance_reservation) {
 
402
         old_logging = schedd_mes_get_logging();
 
403
         schedd_mes_set_logging(0);
 
404
         schedd_mes_off();
 
405
      }
 
406
 
 
407
      for_each(pe, pe_list) {
 
408
         int available_slots = 0;
 
409
 
 
410
         if (!pe_is_matching(pe, pe_request)) {
 
411
            continue;
 
412
         }   
 
413
 
 
414
         matched_pe_count++;
 
415
 
 
416
         pe_name = lGetString(pe, PE_name);
 
417
         if (best->gdil == NULL) { /* first pe run */
 
418
            best->pe = pe;
 
419
            best->pe_name = pe_name;
 
420
 
 
421
            /* determine earliest start time with that PE */
 
422
            result = parallel_reservation_max_time_slots(best, &available_slots);
 
423
            if (result != DISPATCH_OK) {
 
424
               schedd_mes_add(best->job_id, SCHEDD_INFO_PESLOTSNOTINRANGE_SI, pe_name, available_slots); 
 
425
               best_result = find_best_result(best_result, result);
 
426
               continue;
 
427
            }
 
428
            DPRINTF(("### first ### reservation in PE \"%s\" at "sge_u32" with %d soft violations\n",
 
429
                  pe_name, best->start, best->soft_violations));
 
430
         } else { /* test with all other pes */
 
431
            sge_assignment_t tmp = SGE_ASSIGNMENT_INIT;
 
432
 
 
433
            assignment_copy(&tmp, best, false);
 
434
            tmp.pe = pe;
 
435
            tmp.pe_name = pe_name;
 
436
 
 
437
            /* try to find earlier assignment again with minimum slot amount */
 
438
            tmp.slots = 0;
 
439
            result = parallel_reservation_max_time_slots(&tmp, &available_slots); 
 
440
            
 
441
            if (result != DISPATCH_OK) {
 
442
               schedd_mes_add(best->job_id, SCHEDD_INFO_PESLOTSNOTINRANGE_SI, pe_name, available_slots); 
 
443
               best_result = find_best_result(best_result, result);
 
444
               assignment_release(&tmp);
 
445
               continue;
 
446
            }
 
447
 
 
448
            if (tmp.start < best->start || 
 
449
                  (tmp.start == best->start && tmp.soft_violations < best->soft_violations)) {
 
450
               assignment_copy(best, &tmp, true);
 
451
               DPRINTF(("### better ### reservation in PE \"%s\" at "sge_u32" with %d soft violations\n",
 
452
                     pe_name, best->start, best->soft_violations));
 
453
            }
 
454
 
 
455
            assignment_release(&tmp);
 
456
         }
 
457
      }
 
458
   } else {
 
459
      u_long32 ar_id;
 
460
      /* now assignments */ 
 
461
 
 
462
      result = match_static_advance_reservation(best);
 
463
      if (result != DISPATCH_OK) {
 
464
         DRETURN(result);
 
465
      }
 
466
 
 
467
      if ((ar_id = lGetUlong(best->job, JB_ar)) != 0) {
 
468
         lListElem *ar = lGetElemUlong(best->ar_list, AR_id, ar_id);
 
469
         pe = lGetElemStr(pe_list, PE_name, lGetString(ar, AR_granted_pe));
 
470
 
 
471
         if (pe == NULL) {
 
472
            DPRINTF(("Critical Error, ar references non existing PE\n"));
 
473
         } else {
 
474
            int available_slots = 0;
 
475
 
 
476
            matched_pe_count++;
 
477
            best->pe = pe;
 
478
            best->pe_name = lGetString(pe, PE_name);
 
479
 
 
480
            best_result = parallel_maximize_slots_pe(best, &available_slots);
 
481
            if (best_result != DISPATCH_OK) {
 
482
               schedd_mes_add(best->job_id, SCHEDD_INFO_PESLOTSNOTINRANGE_SI, best->pe_name, available_slots); 
 
483
            }
 
484
            DPRINTF(("### AR ### assignment in PE \"%s\" with %d soft violations and %d available slots\n",
 
485
                  best->pe_name, best->soft_violations, available_slots));
 
486
         }
 
487
      } else { 
 
488
         for_each(pe, pe_list) {
 
489
 
 
490
            if (!pe_is_matching(pe, pe_request)) {
 
491
               continue;
 
492
            }
 
493
 
 
494
            pe_name = lGetString(pe, PE_name);
 
495
            matched_pe_count++;
 
496
 
 
497
            if (best->gdil == NULL) {
 
498
               int available_slots = 0;
 
499
               best->pe = pe;
 
500
               best->pe_name = pe_name;
 
501
               result = parallel_maximize_slots_pe(best, &available_slots);
 
502
 
 
503
               if (result != DISPATCH_OK) {
 
504
                  schedd_mes_add(best->job_id, SCHEDD_INFO_PESLOTSNOTINRANGE_SI, pe_name, available_slots); 
 
505
                  best_result = find_best_result(best_result, result);
 
506
                  continue;
 
507
               }
 
508
               DPRINTF(("### first ### assignment in PE \"%s\" with %d soft violations\n",
 
509
                     pe_name, best->soft_violations));
 
510
            } else {
 
511
               int available_slots = 0;
 
512
               sge_assignment_t tmp = SGE_ASSIGNMENT_INIT;
 
513
 
 
514
               assignment_copy(&tmp, best, false);
 
515
               tmp.pe = pe;
 
516
               tmp.pe_name = pe_name;
 
517
 
 
518
               result = parallel_maximize_slots_pe(&tmp, &available_slots);
 
519
                           
 
520
               if (result != DISPATCH_OK) {
 
521
                  assignment_release(&tmp);
 
522
                  schedd_mes_add(best->job_id, SCHEDD_INFO_PESLOTSNOTINRANGE_SI, pe_name, available_slots); 
 
523
                  best_result = find_best_result(best_result, result);
 
524
                  continue;
 
525
               }
 
526
 
 
527
               if ((tmp.slots > best->slots) || 
 
528
                   (tmp.start == best->start && 
 
529
                    tmp.soft_violations < best->soft_violations)) {
 
530
                  assignment_copy(best, &tmp, true);
 
531
                  DPRINTF(("### better ### assignment in PE \"%s\" with %d soft violations\n",
 
532
                           pe_name, best->soft_violations));
 
533
               }
 
534
 
 
535
               assignment_release(&tmp);
 
536
            }
 
537
         }
 
538
      }
 
539
   }
 
540
 
 
541
   if (matched_pe_count == 0) {
 
542
      schedd_mes_add(best->job_id, SCHEDD_INFO_NOPEMATCH_ ); 
 
543
      best_result = DISPATCH_NEVER_CAT;
 
544
   } else if (best->is_reservation && best->gdil) {
 
545
      int available_slots = 0;
 
546
      result = parallel_maximize_slots_pe(best, &available_slots);
 
547
      if (result != DISPATCH_OK) { /* ... should never happen */
 
548
         best_result = DISPATCH_NEVER_CAT;
 
549
      }
 
550
   }
 
551
 
 
552
   if (best->gdil) {
 
553
      best_result = DISPATCH_OK;
 
554
   }   
 
555
 
 
556
   switch (best_result) {
 
557
   case DISPATCH_OK:
 
558
      DPRINTF(("SELECT PE("sge_u32"."sge_u32") returns PE %s %d slots at "sge_u32")\n", 
 
559
            best->job_id, best->ja_task_id, best->pe_name, best->slots, best->start));
 
560
      break;
 
561
   case DISPATCH_NOT_AT_TIME:
 
562
      DPRINTF(("SELECT PE("sge_u32"."sge_u32") returns <later>\n", 
 
563
            best->job_id, best->ja_task_id)); 
 
564
      break;
 
565
   case DISPATCH_NEVER_CAT:
 
566
      DPRINTF(("SELECT PE("sge_u32"."sge_u32") returns <category_never>\n", 
 
567
            best->job_id, best->ja_task_id)); 
 
568
      break;
 
569
   case DISPATCH_NEVER_JOB:
 
570
      DPRINTF(("SELECT PE("sge_u32"."sge_u32") returns <job_never>\n", 
 
571
            best->job_id, best->ja_task_id)); 
 
572
      break;
 
573
   case DISPATCH_MISSING_ATTR:   
 
574
   default:
 
575
      DPRINTF(("!!!!!!!! SELECT PE("sge_u32"."sge_u32") returns unexpected %d\n", 
 
576
            best->job_id, best->ja_task_id, best_result));
 
577
      break;
 
578
   }
 
579
 
 
580
   if (best->is_reservation && !best->is_advance_reservation) {
 
581
      schedd_mes_on();
 
582
      schedd_mes_set_logging(old_logging);
 
583
   }   
 
584
 
 
585
   /* clean up */
 
586
   clean_up_parallel_job(best); 
 
587
   
 
588
   DRETURN(best_result);
 
589
}
 
590
 
 
591
/****** sge_select_queue/clean_up_parallel_job() *******************************
 
592
*  NAME
 
593
*     clean_up_parallel_job() -- removes tages
 
594
*
 
595
*  SYNOPSIS
 
596
*     static void clean_up_parallel_job(sge_assignment_t *a) 
 
597
*
 
598
*  FUNCTION
 
599
*     duing pe job dispatch are man queues and hosts taged. This
 
600
*     function removes the tages.
 
601
*
 
602
*  INPUTS
 
603
*     sge_assignment_t *a - the resource structure
 
604
*
 
605
*
 
606
*
 
607
*  NOTES
 
608
*     MT-NOTE: clean_up_parallel_job() is not MT safe 
 
609
*
 
610
*******************************************************************************/
 
611
static
 
612
void clean_up_parallel_job(sge_assignment_t *a) 
 
613
{
 
614
   lListElem *host = NULL;
 
615
   qinstance_list_set_tag(a->queue_list, 0);
 
616
   for_each(host, a->host_list) {
 
617
      lSetUlong(host, EH_tagged, 0);
 
618
      lSetUlong(host, EH_master_host, 0); 
 
619
   }  
 
620
 
 
621
}
 
622
 
 
623
/****** scheduler/parallel_reservation_max_time_slots() *****************************************
 
624
*  NAME
 
625
*     parallel_reservation_max_time_slots() -- Search earliest possible assignment 
 
626
*
 
627
*  SYNOPSIS
 
628
*     static dispatch_t parallel_reservation_max_time_slots(sge_assignment_t *best) 
 
629
*
 
630
*  FUNCTION
 
631
*     The earliest possible assignment is searched for a job assuming a 
 
632
*     particular parallel environment be used with a particular slot
 
633
*     number. If the slot number passed is 0 we start with the minimum 
 
634
*     possible slot number for that job. The search starts with the 
 
635
*     latest queue end time if DISPATCH_TIME_QUEUE_END was specified 
 
636
*     rather than a real time value.
 
637
*
 
638
*  INPUTS
 
639
*     sge_assignment_t *best - herein we keep all important in/out information
 
640
*
 
641
*  RESULT
 
642
*     dispatch_t - 0 ok got an assignment
 
643
*                  1 no assignment at the specified time (???)
 
644
*                 -1 assignment will never be possible for all jobs of that category
 
645
*                 -2 assignment will never be possible for that particular job
 
646
*
 
647
*  NOTES
 
648
*     MT-NOTE: parallel_reservation_max_time_slots() is not MT safe 
 
649
*******************************************************************************/
 
650
static dispatch_t 
 
651
parallel_reservation_max_time_slots(sge_assignment_t *best, int *available_slots) 
 
652
{
 
653
   u_long32 pe_time, first_time;
 
654
   sge_assignment_t tmp_assignment = SGE_ASSIGNMENT_INIT;
 
655
   dispatch_t result = DISPATCH_NEVER_CAT; 
 
656
   sge_qeti_t *qeti = NULL;
 
657
   bool is_first = true;
 
658
   int old_logging = 0;
 
659
   category_use_t use_category;
 
660
   
 
661
   DENTER(TOP_LAYER, "parallel_reservation_max_time_slots");
 
662
 
 
663
   /* assemble job category information */
 
664
   fill_category_use_t(best, &use_category, best->pe_name);  
 
665
 
 
666
   qeti = sge_qeti_allocate(best->job, best->pe, best->ckpt, 
 
667
         best->host_list, best->queue_list, best->centry_list, best->acl_list, best->hgrp_list, best->ar_list); 
 
668
   if (qeti == NULL) {
 
669
      ERROR((SGE_EVENT, "could not allocate qeti object needed reservation "
 
670
            "scheduling of parallel job "sge_U32CFormat, sge_u32c(best->job_id)));
 
671
      DRETURN(DISPATCH_NEVER_CAT);
 
672
   }
 
673
 
 
674
   assignment_copy(&tmp_assignment, best, false);
 
675
   if (best->slots == 0) {
 
676
      tmp_assignment.slots = range_list_get_first_id(lGetList(best->job, JB_pe_range), NULL);
 
677
   }   
 
678
 
 
679
   if (best->start == DISPATCH_TIME_QUEUE_END) {
 
680
      first_time = sge_qeti_first(qeti);
 
681
      if (first_time == 0) { /* we need at least one reservation run */
 
682
         first_time = sconf_get_now();
 
683
      }
 
684
   } else {
 
685
      /* the first iteration will be done using best->start 
 
686
         further ones will use earliert times */
 
687
      first_time = best->start;
 
688
      sge_qeti_next_before(qeti, best->start);
 
689
   }
 
690
 
 
691
   old_logging = schedd_mes_get_logging(); /* store logging mode */  
 
692
   for (pe_time = first_time ; pe_time; pe_time = sge_qeti_next(qeti)) {
 
693
      DPRINTF(("SELECT PE TIME(%s, "sge_u32") tries at "sge_u32"\n", 
 
694
               best->pe_name, best->job_id, pe_time));
 
695
      tmp_assignment.start = pe_time;
 
696
 
 
697
      /* this is an additional run, we have already at least one posible match,
 
698
         all additional scheduling information is not important, since we can
 
699
         start the job */
 
700
      if (is_first) {
 
701
         is_first = false;
 
702
      } else {
 
703
         use_category.mod_category = false;
 
704
         schedd_mes_set_logging(0);
 
705
         schedd_mes_off();
 
706
      }
 
707
      
 
708
      result = parallel_assignment(&tmp_assignment, &use_category, available_slots);
 
709
      assignment_clear_cache(&tmp_assignment);
 
710
 
 
711
      if (result == DISPATCH_OK) {
 
712
         if (tmp_assignment.gdil) {
 
713
            DPRINTF(("SELECT PE TIME: earlier assignment at "sge_u32"\n", pe_time));
 
714
         }
 
715
         assignment_copy(best, &tmp_assignment, true);
 
716
         assignment_release(&tmp_assignment);
 
717
      } else {
 
718
         DPRINTF(("SELECT PE TIME: no earlier assignment at "sge_u32"\n", pe_time));
 
719
         break;
 
720
      }
 
721
   }
 
722
   schedd_mes_set_logging(old_logging); /* restore logging mode */
 
723
   schedd_mes_on();
 
724
 
 
725
   sge_qeti_release(&qeti);
 
726
   assignment_release(&tmp_assignment);
 
727
 
 
728
   if (best->gdil) {
 
729
      result = DISPATCH_OK;
 
730
   }   
 
731
  
 
732
   switch (result) {
 
733
   case DISPATCH_OK:
 
734
      DPRINTF(("SELECT PE TIME(%s, %d) returns "sge_u32"\n", 
 
735
            best->pe_name, best->slots, best->start));
 
736
      break;
 
737
   case DISPATCH_NEVER_CAT:
 
738
      DPRINTF(("SELECT PE TIME(%s, %d) returns <category_never>\n", 
 
739
            best->pe_name, best->slots));
 
740
      break;
 
741
   case DISPATCH_NEVER_JOB:
 
742
      DPRINTF(("SELECT PE TIME(%s, %d) returns <job_never>\n", 
 
743
            best->pe_name, best->slots));
 
744
      break;
 
745
   default:
 
746
      DPRINTF(("!!!!!!!! SELECT PE TIME(%s, %d) returns unexpected %d\n", 
 
747
            best->pe_name, best->slots, result));
 
748
      break;
 
749
   }
 
750
 
 
751
   DRETURN(result);
 
752
}
 
753
 
 
754
/****** scheduler/parallel_maximize_slots_pe() *****************************************
 
755
*  NAME
 
756
*     parallel_maximize_slots_pe() -- Maximize number of slots for an assignment
 
757
*
 
758
*  SYNOPSIS
 
759
*     static int parallel_maximize_slots_pe(sge_assignment_t *best, lList *host_list, 
 
760
*     lList *queue_list, lList *centry_list, lList *acl_list) 
 
761
*
 
762
*  FUNCTION
 
763
*     The largest possible slot amount is searched for a job assuming a 
 
764
*     particular parallel environment be used at a particular start time. 
 
765
*     If the slot number passed is 0 we start with the minimum 
 
766
*     possible slot number for that job.
 
767
*
 
768
*     To search most efficent for the right slot value, it has three search
 
769
*     strategies implemented:
 
770
*     - binary search
 
771
*     - least slot value first
 
772
*     - highest slot value first
 
773
*
 
774
*     To be able to use binary search all possible slot values are stored in 
 
775
*     one array. The slot values in this array are sorted ascending. After the
 
776
*     right slot value was found, it is very easy to compute the best strategy
 
777
*     from the result. For each strategy it will compute how many iterations
 
778
*     would have been needed to compute the correct result. These steps will
 
779
*     be stored for the next run and used to figure out the best algorithm.
 
780
*     To ensure that we can adapt to rapid changes and also ignore spiks we
 
781
*     are using the running avarage algorithm in a 80-20 setting. This means
 
782
*     that the algorithm will need 4 (max 5) iterations to adopt to a new
 
783
*     secenario. 
 
784
*
 
785
*  Further enhancements:
 
786
*     It might be a good idea to store the derived values with the job cartegories
 
787
*     and allow to find the best strategy per category.
 
788
*
 
789
*  INPUTS
 
790
*     sge_assignment_t *best - herein we keep all important in/out information
 
791
*     lList *host_list       - a list of all available hosts
 
792
*     lList *queue_list      - a list of all available queues
 
793
*     lList *centry_list     - a list of all available complex attributes
 
794
*     lList *acl_list        - a list of all access lists
 
795
*
 
796
*  RESULT
 
797
*     int - 0 ok got an assignment (maybe without maximizing it) 
 
798
*           1 no assignment at the specified time
 
799
*          -1 assignment will never be possible for all jobs of that category
 
800
*          -2 assignment will never be possible for that particular job
 
801
*
 
802
*  NOTES
 
803
*     MT-NOTE: parallel_maximize_slots_pe() is MT safe as long as the provided 
 
804
*              lists are owned be the caller
 
805
*
 
806
*  SEE ALSO:
 
807
*     sconf_best_pe_alg
 
808
*     sconf_update_pe_alg
 
809
*     add_pe_slots_to_category
 
810
*
 
811
*******************************************************************************/
 
812
static dispatch_t
 
813
parallel_maximize_slots_pe(sge_assignment_t *best, int *available_slots) 
 
814
{
 
815
 
 
816
   int min_slots, max_slots; 
 
817
   int max_pe_slots;
 
818
   int first, last;
 
819
   lList *pe_range;
 
820
   lListElem *pe;
 
821
   sge_assignment_t tmp = SGE_ASSIGNMENT_INIT;
 
822
   dispatch_t result = DISPATCH_NEVER_CAT; 
 
823
   const char *pe_name = best->pe_name;
 
824
   bool is_first = true;
 
825
   int old_logging = 0;
 
826
   category_use_t use_category;
 
827
   u_long32 max_slotsp = 0;
 
828
   int current = 0;
 
829
   int match_current = 0;
 
830
   int runs = 0;
 
831
   schedd_pe_algorithm alg =  sconf_best_pe_alg();
 
832
 
 
833
   DENTER(TOP_LAYER, "parallel_maximize_slots_pe");
 
834
 
 
835
   if (best == NULL || 
 
836
       (pe_range=lGetList(best->job, JB_pe_range)) == NULL || 
 
837
       (pe=best->pe) == NULL) {
 
838
      DRETURN(DISPATCH_NEVER_CAT);
 
839
   }
 
840
 
 
841
   /* assemble job category information */
 
842
   fill_category_use_t(best, &use_category, pe_name);      
 
843
 
 
844
   first = range_list_get_first_id(pe_range, NULL);
 
845
   last  = range_list_get_last_id(pe_range, NULL);
 
846
   max_pe_slots = lGetUlong(pe, PE_slots);
 
847
 
 
848
   if (best->slots) {
 
849
      min_slots = best->slots;
 
850
   } else {
 
851
      min_slots = first;
 
852
   }   
 
853
 
 
854
   if (best->gdil || best->slots == max_pe_slots) { /* already found maximum */
 
855
      DRETURN(DISPATCH_OK); 
 
856
   }
 
857
 
 
858
   DPRINTF(("MAXIMIZE SLOT: FIRST %d LAST %d MAX SLOT %d\n", first, last, max_pe_slots));
 
859
 
 
860
   /* this limits max range number RANGE_INFINITY (i.e. -pe pe 1-) to reasonable number */
 
861
   max_slots = MIN(last, max_pe_slots);
 
862
 
 
863
   DPRINTF(("MAXIMIZE SLOT FOR "sge_u32" using \"%s\" FROM %d TO %d\n", 
 
864
      best->job_id, pe_name, min_slots, max_slots));
 
865
 
 
866
   old_logging = schedd_mes_get_logging(); /* store logging mode */  
 
867
 
 
868
   if ((max_slots < min_slots) ||
 
869
      (min_slots <= 0)) {
 
870
      ERROR((SGE_EVENT, "invalid pe job range setting for job "sge_u32"\n", best->job_id));
 
871
      DRETURN(DISPATCH_NEVER_CAT);
 
872
   }
 
873
 
 
874
   /* --- prepare the posible slots for the binary search */
 
875
   max_slotsp = (max_slots - min_slots+1);
 
876
   if (!add_pe_slots_to_category(&use_category, &max_slotsp, pe, min_slots, max_slots, pe_range)) {
 
877
      ERROR((SGE_EVENT, MSG_SGETEXT_NOMEM));
 
878
      DRETURN(DISPATCH_NEVER_CAT);
 
879
   }
 
880
   if (max_slotsp == 0) {
 
881
      DPRINTF(("no slots in PE %s available for job "sge_u32"\n", pe_name, best->job_id));     
 
882
      DRETURN(DISPATCH_NEVER_CAT);
 
883
   }
 
884
   
 
885
   assignment_copy(&tmp, best, false);
 
886
 
 
887
   /* --- work on the different slot ranges and try to find the best one --- */
 
888
   if (alg == SCHEDD_PE_BINARY) {
 
889
      int min = 0; 
 
890
      int max = max_slotsp-1;
 
891
         
 
892
      do {
 
893
         runs++;
 
894
         current = (min + max) / 2;
 
895
       
 
896
         if (is_first) { /* first run, collect information */
 
897
            is_first = false;
 
898
         } else { /* this is an additional run, we have already at least one posible match */
 
899
            use_category.mod_category = false;
 
900
            schedd_mes_set_logging(0);
 
901
            schedd_mes_off();
 
902
         }
 
903
 
 
904
         /* we try that slot amount */
 
905
         tmp.slots = use_category.posible_pe_slots[current];
 
906
         result = parallel_assignment(&tmp, &use_category, available_slots);         
 
907
         assignment_clear_cache(&tmp);
 
908
        
 
909
         if (result == DISPATCH_OK) {
 
910
            assignment_copy(best, &tmp, true);
 
911
            assignment_release(&tmp);
 
912
            match_current = current;
 
913
            min = current + 1;
 
914
         } else {
 
915
            max = current - 1;
 
916
         }
 
917
         
 
918
      } while (min <= max && max != -1);
 
919
      
 
920
   } else {
 
921
      /* compute how many runs the bin search might have needed */
 
922
      /* This will not give us the correct answer in all cases, but
 
923
         it is close enough. And on average it is corrent :-) */
 
924
      int end = max_slotsp;
 
925
      for ( runs=1; runs < end; runs++) {
 
926
         end = end - runs;
 
927
      }
 
928
      runs--;
 
929
 
 
930
      if (alg == SCHEDD_PE_LOW_FIRST) {
 
931
         for (current = 0; current < max_slotsp; current++) {
 
932
 
 
933
            if (is_first) { /* first run, collect information */
 
934
               is_first = false;
 
935
            } else {  /* this is an additional run, we have already at least one posible match */
 
936
               use_category.mod_category = false;
 
937
               schedd_mes_set_logging(0);
 
938
               schedd_mes_off();
 
939
            }
 
940
 
 
941
            /* we try that slot amount */ 
 
942
            tmp.slots = use_category.posible_pe_slots[current];
 
943
            result = parallel_assignment(&tmp, &use_category, available_slots);
 
944
            assignment_clear_cache(&tmp);
 
945
 
 
946
            if (result != DISPATCH_OK) { /* we have mismatch, stop */
 
947
               break;                    /* the other runs will not work */
 
948
            }   
 
949
            
 
950
            match_current = current;
 
951
            assignment_copy(best, &tmp, true);
 
952
            assignment_release(&tmp);
 
953
         }
 
954
      } else { /* optimistic search */
 
955
         for (current = max_slotsp-1; current >= 0; current--) {
 
956
 
 
957
            if (is_first) { /* first run, collect information */
 
958
               is_first = false;
 
959
            } else { /* this is an additional run, we have already at least one posible match */
 
960
               use_category.mod_category = false;
 
961
               schedd_mes_set_logging(0);
 
962
               schedd_mes_off();
 
963
            }
 
964
 
 
965
            /* we try that slot amount */ 
 
966
            tmp.slots = use_category.posible_pe_slots[current];
 
967
            result = parallel_assignment(&tmp, &use_category, available_slots);
 
968
            assignment_clear_cache(&tmp);
 
969
 
 
970
            if (result == DISPATCH_OK) {          /* we have a match, stop */
 
971
               assignment_copy(best, &tmp, true); /* all other runs will also match */
 
972
               assignment_release(&tmp);
 
973
               match_current = current;
 
974
               break;
 
975
            }
 
976
         } /* end for */
 
977
      }
 
978
      
 
979
   } /* end for */
 
980
  
 
981
   sconf_update_pe_alg(runs, match_current, max_slotsp);
 
982
 
 
983
   
 
984
   /* --- we are done --- */
 
985
   if (!use_category.is_pe_slots_rev) {
 
986
      FREE(use_category.posible_pe_slots);
 
987
   }
 
988
 
 
989
   assignment_release(&tmp);   
 
990
 
 
991
   schedd_mes_set_logging(old_logging); /* restore logging mode */
 
992
   schedd_mes_on();
 
993
 
 
994
   if (best->gdil) {
 
995
      result = DISPATCH_OK;
 
996
   }   
 
997
 
 
998
   switch (result) {
 
999
      case DISPATCH_OK:
 
1000
 
 
1001
         if (!best->is_reservation) { 
 
1002
            sconf_inc_comprehensive_jobs();
 
1003
         }   
 
1004
         
 
1005
         DPRINTF(("MAXIMIZE SLOT(%s, %d) returns <ok>\n", 
 
1006
                  pe_name, best->slots));
 
1007
         break;
 
1008
      case DISPATCH_NOT_AT_TIME:
 
1009
         DPRINTF(("MAXIMIZE SLOT(%s, %d) returns <later>\n", 
 
1010
               pe_name, best->slots));
 
1011
         break;
 
1012
      case DISPATCH_NEVER_CAT:
 
1013
         DPRINTF(("MAXIMIZE SLOT(%s, %d) returns <category_never>\n", 
 
1014
               pe_name, best->slots));
 
1015
         break;
 
1016
      case DISPATCH_NEVER_JOB:
 
1017
         DPRINTF(("MAXIMIZE SLOT(%s, %d) returns <job_never>\n", 
 
1018
               pe_name, best->slots));
 
1019
         break;
 
1020
      default:
 
1021
         DPRINTF(("!!!!!!!! MAXIMIZE SLOT(%d, %d) returns unexpected %d\n", 
 
1022
               best->slots, (int)best->start, result));
 
1023
         break;
 
1024
   }
 
1025
 
 
1026
   DRETURN(result);
 
1027
}
 
1028
 
 
1029
/****** sge_select_queue/sge_select_queue() ************************************
 
1030
*  NAME
 
1031
*     sge_select_queue() -- checks whether a job matches a given queue or host 
 
1032
*
 
1033
*  SYNOPSIS
 
1034
*     int sge_select_queue(lList *requested_attr, lListElem *queue, lListElem 
 
1035
*     *host, lList *exechost_list, lList *centry_list, bool 
 
1036
*     allow_non_requestable, int slots) 
 
1037
*
 
1038
*  FUNCTION
 
1039
*     Takes the requested attributes from a job and checks if it matches the given
 
1040
*     host or queue. One and only one should be specified. If both, the function
 
1041
*     assumes, that the queue belongs to the given host. 
 
1042
*
 
1043
*  INPUTS
 
1044
*     lList *requested_attr     - list of requested attributes 
 
1045
*     lListElem *queue          - current queue or null if host is set
 
1046
*     lListElem *host           - current host or null if queue is set
 
1047
*     lList *exechost_list      - list of all hosts in the system
 
1048
*     lList *centry_list        - system wide attribut config list
 
1049
*     bool allow_non_requestable - allow non requestable?
 
1050
*     int slots                 - number of requested slots
 
1051
*     lList *queue_user_list    - list of users or null
 
1052
*     lList *acl_list           - acl_list or null
 
1053
*     lListElem *job            - job or null
 
1054
*
 
1055
*  RESULT
 
1056
*     int - 1, if okay, QU_tag will be set if a queue is selected
 
1057
*           0, if not okay 
 
1058
*  
 
1059
*  NOTES
 
1060
*   The caller is responsible for cleaning tags.   
 
1061
*
 
1062
*   No range is used. For serial jobs we will need a call for hard and one
 
1063
*    for soft requests. For parallel jobs we will call this function for each
 
1064
*   -l request. Because of in serial jobs requests can be simply added.
 
1065
*   In Parallel jobs each -l requests a different set of queues.
 
1066
*
 
1067
*******************************************************************************/
 
1068
bool 
 
1069
sge_select_queue(lList *requested_attr, lListElem *queue, lListElem *host, 
 
1070
                 lList *exechost_list, lList *centry_list, bool allow_non_requestable, 
 
1071
                 int slots, lList *queue_user_list, lList *acl_list, lListElem *job) 
 
1072
{
 
1073
   dispatch_t ret;
 
1074
   lList *load_attr = NULL;
 
1075
   lList *config_attr = NULL;
 
1076
   lList *actual_attr = NULL; 
 
1077
   lListElem *global = NULL;
 
1078
   lListElem *qu = NULL;
 
1079
   int q_access=1;
 
1080
   lList *projects;
 
1081
   const char *project;
 
1082
    
 
1083
   sge_assignment_t a = SGE_ASSIGNMENT_INIT;
 
1084
   double lc_factor = 0; /* scaling for load correction */ 
 
1085
   u_long32 ulc_factor; 
 
1086
   /* actually we don't care on start time here to this is just a dummy setting */
 
1087
   u_long32 start_time = DISPATCH_TIME_NOW; 
 
1088
 
 
1089
   DENTER(TOP_LAYER, "sge_select_queue");
 
1090
 
 
1091
   clear_resource_tags(requested_attr, MAX_TAG);
 
1092
 
 
1093
   assignment_init(&a, NULL, NULL, false);
 
1094
   a.centry_list      = centry_list;
 
1095
   a.host_list        = exechost_list;
 
1096
 
 
1097
   if (acl_list != NULL) {
 
1098
      /* check if job owner has access rights to the queue */
 
1099
      DPRINTF(("testing queue access lists\n"));
 
1100
      for_each(qu, queue_user_list) {
 
1101
         const char *name = lGetString(qu, ST_name);
 
1102
         DPRINTF(("-----> checking queue user: %s\n", name ));
 
1103
         q_access |= (name[0]=='@')?
 
1104
                     sge_has_access(NULL, &name[1], queue, acl_list): 
 
1105
                     sge_has_access(name, NULL, queue, acl_list); 
 
1106
      }
 
1107
      if (q_access == 0) {
 
1108
         DPRINTF(("no access\n"));
 
1109
         assignment_release(&a);
 
1110
         DRETURN(false); 
 
1111
      } else {
 
1112
         DPRINTF(("ok\n"));
 
1113
      }
 
1114
   }
 
1115
 
 
1116
   if (job != NULL) {
 
1117
      /* check if job can run in queue based on project */
 
1118
      DPRINTF(("testing job projects lists\n"));
 
1119
      if ( (project = lGetString(job, JB_project)) ) { 
 
1120
         if ((!(projects = lGetList(queue, QU_projects)))) {
 
1121
            DPRINTF(("no access because queue has no project\n"));
 
1122
            assignment_release(&a);
 
1123
            DRETURN(false);
 
1124
         }
 
1125
         if ((!prj_list_locate(projects, project))) {
 
1126
            DPRINTF(("no access because project not contained in queues project list"));
 
1127
            assignment_release(&a);
 
1128
            DRETURN(false);
 
1129
         }
 
1130
         DPRINTF(("ok\n"));
 
1131
 
 
1132
         /* check if job can run in queue based on excluded projects */
 
1133
         DPRINTF(("testing job xprojects lists\n"));
 
1134
         if ((projects = lGetList(queue, QU_xprojects))) {
 
1135
            if (((project = lGetString(job, JB_project)) &&
 
1136
                 prj_list_locate(projects, project))) {
 
1137
               DPRINTF(("no access\n"));
 
1138
               assignment_release(&a);
 
1139
               DRETURN(false);
 
1140
            }
 
1141
         }
 
1142
         DPRINTF(("ok\n"));
 
1143
      }
 
1144
 
 
1145
      /* 
 
1146
      *is queue contained in hard queue list ?
 
1147
      */
 
1148
      DPRINTF(("queue contained in jobs hard queue list?\n"));
 
1149
      if (lGetList(job, JB_hard_queue_list)) {
 
1150
         lList *qref_list = lGetList(job, JB_hard_queue_list);
 
1151
         const char *qname = NULL;
 
1152
         const char *qinstance_name = NULL;
 
1153
 
 
1154
         qname = lGetString(queue, QU_qname);
 
1155
         qinstance_name = lGetString(queue, QU_full_name);
 
1156
         if ((lGetElemStr(qref_list, QR_name, qname) != NULL) || 
 
1157
             (lGetElemStr(qref_list, QR_name, qinstance_name) != NULL)) {
 
1158
            DPRINTF(("ok"));
 
1159
         } else {
 
1160
            DPRINTF(("denied because queue \"%s\" is not contained in the hard "
 
1161
                     "queue list (-q) that was requested by job %d\n",
 
1162
                     qname, lGetUlong(job, JB_job_number)));
 
1163
            assignment_release(&a);
 
1164
            DRETURN(false);
 
1165
         }
 
1166
      }
 
1167
   }
 
1168
 
 
1169
/* global */
 
1170
   global = host_list_locate(exechost_list, SGE_GLOBAL_NAME);
 
1171
   load_attr = lGetList(global, EH_load_list); 
 
1172
   config_attr = lGetList(global, EH_consumable_config_list);
 
1173
   actual_attr = lGetList(global, EH_resource_utilization);
 
1174
 
 
1175
   /* is there a multiplier for load correction (may be not in qstat, qmon etc) */
 
1176
   if (lGetPosViaElem(global, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
1177
      if ((ulc_factor=lGetUlong(global, EH_load_correction_factor)))
 
1178
         lc_factor = ((double)ulc_factor)/100;
 
1179
   } 
 
1180
 
 
1181
   ret = rc_time_by_slots(&a, requested_attr, load_attr, config_attr, actual_attr, 
 
1182
            NULL, allow_non_requestable, NULL, slots, DOMINANT_LAYER_HOST, lc_factor, GLOBAL_TAG,
 
1183
            &start_time, SGE_GLOBAL_NAME);
 
1184
 
 
1185
/* host */
 
1186
   if(ret == DISPATCH_OK || ret == DISPATCH_MISSING_ATTR){
 
1187
      if(host == NULL) {
 
1188
         host = host_list_locate(exechost_list, lGetHost(queue, QU_qhostname));
 
1189
      }   
 
1190
      load_attr = lGetList(host, EH_load_list); 
 
1191
      config_attr = lGetList(host, EH_consumable_config_list);
 
1192
      actual_attr = lGetList(host, EH_resource_utilization);
 
1193
 
 
1194
      if (lGetPosViaElem(host, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
1195
         if ((ulc_factor=lGetUlong(host, EH_load_correction_factor)))
 
1196
            lc_factor = ((double)ulc_factor)/100;
 
1197
      }
 
1198
 
 
1199
      ret = rc_time_by_slots(&a, requested_attr, load_attr, config_attr, 
 
1200
                             actual_attr, NULL, allow_non_requestable, NULL, 
 
1201
                             slots, DOMINANT_LAYER_HOST, lc_factor, HOST_TAG, 
 
1202
                             &start_time, lGetHost(host, EH_name));
 
1203
 
 
1204
/* queue */
 
1205
     if((ret == DISPATCH_OK || ret == DISPATCH_MISSING_ATTR) && queue){
 
1206
         config_attr = lGetList(queue, QU_consumable_config_list);
 
1207
         actual_attr = lGetList(queue, QU_resource_utilization);
 
1208
   
 
1209
         ret = rc_time_by_slots(&a, requested_attr, NULL, config_attr, actual_attr,  
 
1210
               queue, allow_non_requestable, NULL, slots, DOMINANT_LAYER_QUEUE, 0, QUEUE_TAG, 
 
1211
               &start_time,  lGetString(queue, QU_full_name));
 
1212
      }
 
1213
   }
 
1214
 
 
1215
   assignment_release(&a);
 
1216
   
 
1217
   DRETURN((ret == DISPATCH_OK) ? true : false);
 
1218
}
 
1219
 
 
1220
 
 
1221
/****** sge_select_queue/rc_time_by_slots() **********************************
 
1222
*  NAME
 
1223
*     rc_time_by_slots() -- checks weather all resource requests on one level
 
1224
*                             are fulfilled 
 
1225
*
 
1226
*  SYNOPSIS
 
1227
*     static int rc_time_by_slots(lList *requested, lList *load_attr, lList 
 
1228
*     *config_attr, lList *actual_attr, lList *centry_list, lListElem *queue, 
 
1229
*     bool allow_non_requestable, char *reason, int reason_size, int slots, 
 
1230
*     u_long32 layer, double lc_factor, u_long32 tag) 
 
1231
*
 
1232
*  FUNCTION
 
1233
*     Checks, weather all requests, default requests and implicit requests on this
 
1234
*     this level are fulfilled.
 
1235
*
 
1236
*     With reservation scheduling the earliest start time due to resources of the 
 
1237
*     resource container is the maximum of the earliest start times for all 
 
1238
*     resources comprised by the resource container that requested by a job.
 
1239
*
 
1240
*  INPUTS
 
1241
*     lList *requested          - list of attribute requests 
 
1242
*     lList *load_attr          - list of load attributes or null on queue level
 
1243
*     lList *config_attr        - list of user defined attributes 
 
1244
*     lList *actual_attr        - usage of all consumables (RUE_Type)
 
1245
*     lList *centry_list        - system wide attribute config. list (CE_Type)
 
1246
*     lListElem *queue          - current queue or NULL on global/host level
 
1247
*     bool allow_non_requestable - allow none requestabales? 
 
1248
*     char *reason              - error message
 
1249
*     int reason_size           - max error message size
 
1250
*     int slots                 - number of slots the job is looking for 
 
1251
*     u_long32 layer            - current layer flag 
 
1252
*     double lc_factor          - load correction factor 
 
1253
*     u_long32 tag              - current layer tag 
 
1254
*     u_long32 *start_time      - in/out argument for start time  
 
1255
*     u_long32 duration         - jobs estimated total run time
 
1256
*     const char *object_name   - name of the object used for monitoring purposes
 
1257
*
 
1258
*  RESULT
 
1259
*     dispatch_t - 
 
1260
*
 
1261
*  NOTES
 
1262
*     MT-NOTES: is not thread save. uses a static buffer
 
1263
*
 
1264
*  Important:
 
1265
*     we have some special behavior, when slots is set to -1.
 
1266
*******************************************************************************/
 
1267
static dispatch_t
 
1268
rc_time_by_slots(const sge_assignment_t *a, lList *requested, lList *load_attr, lList *config_attr, 
 
1269
                 lList *actual_attr, lListElem *queue, bool allow_non_requestable, 
 
1270
                 dstring *reason, int slots, u_long32 layer, double lc_factor, u_long32 tag,
 
1271
                 u_long32 *start_time, const char *object_name) 
 
1272
{
 
1273
   static lListElem *implicit_slots_request = NULL;
 
1274
   lListElem *attr;
 
1275
   u_long32 latest_time = DISPATCH_TIME_NOW;
 
1276
   u_long32 tmp_start;
 
1277
   dispatch_t ret;
 
1278
   bool is_not_found = false;
 
1279
 
 
1280
   DENTER(TOP_LAYER, "rc_time_by_slots");
 
1281
 
 
1282
   clear_resource_tags(requested, QUEUE_TAG); 
 
1283
 
 
1284
   /* ensure availability of implicit slot request */
 
1285
   if (!implicit_slots_request) {
 
1286
      implicit_slots_request = lCreateElem(CE_Type);
 
1287
      lSetString(implicit_slots_request, CE_name, SGE_ATTR_SLOTS);
 
1288
      lSetString(implicit_slots_request, CE_stringval, "1");
 
1289
      lSetDouble(implicit_slots_request, CE_doubleval, 1);
 
1290
   }
 
1291
 
 
1292
   /* match number of free slots */
 
1293
   if (slots != -1) {
 
1294
      tmp_start = *start_time;
 
1295
      ret = ri_time_by_slots(a, implicit_slots_request, load_attr, config_attr, actual_attr, queue,  
 
1296
                       reason, allow_non_requestable, slots, layer, lc_factor, &tmp_start, object_name);
 
1297
 
 
1298
      if (ret == DISPATCH_OK && *start_time == DISPATCH_TIME_QUEUE_END) {
 
1299
         DPRINTF(("%s: \"slot\" request delays start time from "sge_U32CFormat
 
1300
           " to "sge_U32CFormat"\n", object_name, latest_time, MAX(latest_time, tmp_start)));
 
1301
         latest_time = MAX(latest_time, tmp_start);
 
1302
      }
 
1303
 
 
1304
      /* we don't care if slots are not specified, except at queue level */
 
1305
      if (ret == DISPATCH_MISSING_ATTR && tag != QUEUE_TAG) {
 
1306
         ret = DISPATCH_OK;
 
1307
      }   
 
1308
      if (ret != DISPATCH_OK) {
 
1309
         DRETURN(ret);
 
1310
      }
 
1311
   }
 
1312
 
 
1313
   /* ensure all default requests are fulfilled */
 
1314
   if (slots != -1 && !allow_non_requestable) {
 
1315
      lListElem *attr;
 
1316
      dispatch_t ff;
 
1317
      const char *name;
 
1318
      double dval=0.0;
 
1319
      u_long32 valtype;
 
1320
 
 
1321
      for_each (attr, actual_attr) {
 
1322
         name = lGetString(attr, RUE_name);
 
1323
         if (!strcmp(name, "slots")) {
 
1324
            continue;
 
1325
         }
 
1326
 
 
1327
         /* consumable && used in this global/host/queue && not requested */
 
1328
         if (!is_requested(requested, name)) {
 
1329
            lListElem *default_request = lGetElemStr(a->centry_list, CE_name, name);
 
1330
            const char *def_req = lGetString(default_request, CE_default);
 
1331
            valtype = lGetUlong(default_request, CE_valtype);
 
1332
            parse_ulong_val(&dval, NULL, valtype, def_req, NULL, 0);
 
1333
 
 
1334
            /* ignore default request if the value is 0 */
 
1335
            if(def_req != NULL && dval != 0.0) {
 
1336
               dstring tmp_reason;
 
1337
               char tmp_reason_buf[2048];
 
1338
 
 
1339
               sge_dstring_init(&tmp_reason, tmp_reason_buf, sizeof(tmp_reason_buf));
 
1340
 
 
1341
               /* build the default request */
 
1342
               lSetString(default_request, CE_stringval, def_req);
 
1343
               lSetDouble(default_request, CE_doubleval, dval);
 
1344
 
 
1345
               tmp_start = *start_time;
 
1346
               ff = ri_time_by_slots(a, default_request, load_attr, config_attr, actual_attr, 
 
1347
                     queue, &tmp_reason, true, slots, layer, lc_factor, &tmp_start, object_name);
 
1348
 
 
1349
               if (ff != DISPATCH_OK) {
 
1350
                  /* useless to continue in these cases */
 
1351
                  sge_dstring_append(reason, MSG_SCHEDD_FORDEFAULTREQUEST);
 
1352
                  sge_dstring_append_dstring(reason, &tmp_reason);
 
1353
                  DRETURN(ff);
 
1354
               }
 
1355
 
 
1356
               if (*start_time == DISPATCH_TIME_QUEUE_END) {
 
1357
                  DPRINTF(("%s: default request \"%s\" delays start time from "sge_U32CFormat 
 
1358
                        " to "sge_U32CFormat"\n", object_name, name, latest_time, MAX(latest_time, tmp_start)));
 
1359
                  latest_time = MAX(latest_time, tmp_start);
 
1360
               }
 
1361
            } 
 
1362
         } 
 
1363
      }/* end for*/
 
1364
   }
 
1365
 
 
1366
   if (slots == -1) {
 
1367
      slots = 1;
 
1368
   }   
 
1369
   /* explicit requests */
 
1370
   for_each (attr, requested) {
 
1371
      const char *attr_name = lGetString(attr, CE_name);
 
1372
 
 
1373
      tmp_start = *start_time;
 
1374
      switch (ri_time_by_slots(a, attr,load_attr, config_attr, actual_attr, queue, 
 
1375
               reason, allow_non_requestable, slots, layer, lc_factor, &tmp_start, object_name)) {
 
1376
         
 
1377
         case DISPATCH_NEVER_CAT : /* will never match */ 
 
1378
                  DRETURN(DISPATCH_NEVER_CAT);
 
1379
                  
 
1380
         case DISPATCH_OK : /* a match was found */
 
1381
               if (*start_time == DISPATCH_TIME_QUEUE_END) {
 
1382
                  DPRINTF(("%s: explicit request \"%s\" delays start time from "sge_U32CFormat 
 
1383
                           "to "sge_U32CFormat"\n", object_name, attr_name, latest_time, 
 
1384
                           MAX(latest_time, tmp_start)));
 
1385
                  latest_time = MAX(latest_time, tmp_start);
 
1386
               }
 
1387
               if (lGetUlong(attr, CE_tagged) < tag && tag != RQS_TAG) {
 
1388
                  lSetUlong(attr, CE_tagged, tag);
 
1389
               }   
 
1390
            break;
 
1391
            
 
1392
         case DISPATCH_NOT_AT_TIME : /* will match later-on */
 
1393
                  DPRINTF(("%s: request for %s will match later-on\n", object_name, attr_name));
 
1394
                  DRETURN(DISPATCH_NOT_AT_TIME);
 
1395
                  
 
1396
         case DISPATCH_MISSING_ATTR : /* the requested element does not exist */
 
1397
            if (tag == QUEUE_TAG && lGetUlong(attr, CE_tagged) == NO_TAG) {
 
1398
               sge_dstring_sprintf(reason, MSG_SCHEDD_JOBREQUESTSUNKOWNRESOURCE_S, attr_name);
 
1399
               DRETURN(DISPATCH_NEVER_CAT);
 
1400
            }
 
1401
 
 
1402
            if (tag != QUEUE_TAG) {
 
1403
               is_not_found = true;
 
1404
            }
 
1405
 
 
1406
            break;
 
1407
         default: /* error */
 
1408
            break;
 
1409
      }
 
1410
   }
 
1411
 
 
1412
   if (*start_time == DISPATCH_TIME_QUEUE_END) {
 
1413
      *start_time = latest_time;
 
1414
   }
 
1415
 
 
1416
   if (is_not_found) {
 
1417
      DRETURN(DISPATCH_MISSING_ATTR);
 
1418
   } 
 
1419
 
 
1420
   DRETURN(DISPATCH_OK);
 
1421
}
 
1422
 
 
1423
static dispatch_t 
 
1424
match_static_resource(int slots, lListElem *req_cplx, lListElem *src_cplx, dstring *reason,
 
1425
                      int is_threshold, int force_existence, bool allow_non_requestable)
 
1426
{
 
1427
   int match;
 
1428
   dispatch_t ret = DISPATCH_OK;
 
1429
   char availability_text[2048];
 
1430
 
 
1431
   DENTER(TOP_LAYER, "match_static_resource");
 
1432
 
 
1433
   /* check whether attrib is requestable */
 
1434
   if (!allow_non_requestable && lGetUlong(src_cplx, CE_requestable) == REQU_NO) {
 
1435
      sge_dstring_append(reason, MSG_SCHEDD_JOBREQUESTSNONREQUESTABLERESOURCE);
 
1436
      sge_dstring_append(reason, lGetString(src_cplx, CE_name));
 
1437
      sge_dstring_append(reason, "\"");
 
1438
      DRETURN(DISPATCH_NEVER_CAT);
 
1439
   }
 
1440
 
 
1441
   match = compare_complexes(slots, req_cplx, src_cplx, availability_text, false, false);
 
1442
 
 
1443
   if (!match) {
 
1444
      sge_dstring_append(reason, MSG_SCHEDD_ITOFFERSONLY);
 
1445
      sge_dstring_append(reason, availability_text);
 
1446
      ret = DISPATCH_NEVER_CAT;
 
1447
   }
 
1448
 
 
1449
   DRETURN(ret);
 
1450
}
 
1451
 
 
1452
/****** sge_select_queue/clear_resource_tags() *********************************
 
1453
*  NAME
 
1454
*     clear_resource_tags() -- removes the tags from a resouce request. 
 
1455
*
 
1456
*  SYNOPSIS
 
1457
*     static void clear_resource_tags(lList *resouces, u_long32 max_tag) 
 
1458
*
 
1459
*  FUNCTION
 
1460
*     Removes the tages from the given resouce list. A tag is only removed
 
1461
*     if it is smaller or equal to the given tag value. The tag value "MAX_TAG" results
 
1462
*     in removing all existing tags, or the value "HOST_TAG" removes queue and host
 
1463
*     tags but keeps the global tags.
 
1464
*
 
1465
*  INPUTS
 
1466
*     lList *resouces  - list of job requests. 
 
1467
*     u_long32 max_tag - max tag element 
 
1468
*
 
1469
*******************************************************************************/
 
1470
static void clear_resource_tags(lList *resources, u_long32 max_tag) {
 
1471
 
 
1472
   lListElem *attr=NULL;
 
1473
 
 
1474
   for_each(attr, resources){
 
1475
      if(lGetUlong(attr, CE_tagged) <= max_tag)
 
1476
         lSetUlong(attr, CE_tagged, NO_TAG);
 
1477
   }
 
1478
}
 
1479
 
 
1480
 
 
1481
/****** sge_select_queue/sge_queue_match_static() ************************
 
1482
*  NAME
 
1483
*     sge_queue_match_static() -- Do matching that depends not on time.
 
1484
*
 
1485
*  SYNOPSIS
 
1486
*     static int sge_queue_match_static(lListElem *queue, lListElem *job, 
 
1487
*     const lListElem *pe, const lListElem *ckpt, lList *centry_list, lList 
 
1488
*     *host_list, lList *acl_list) 
 
1489
*
 
1490
*  FUNCTION
 
1491
*     Checks if a job fits on a queue or not. All checks that depend on the 
 
1492
*     current load and resource situation must get handled outside. 
 
1493
*     The queue also gets tagged in QU_tagged4schedule to indicate whether it
 
1494
*     is specified using -masterq queue_list.
 
1495
*
 
1496
*  INPUTS
 
1497
*     lListElem *queue      - The queue we're matching
 
1498
*     lListElem *job        - The job
 
1499
*     const lListElem *pe   - The PE object
 
1500
*     const lListElem *ckpt - The ckpt object
 
1501
*     lList *centry_list    - The centry list
 
1502
*     lList *acl_list       - The ACL list
 
1503
*
 
1504
*  RESULT
 
1505
*     dispatch_t - DISPATCH_OK, ok
 
1506
*                  DISPATCH_NEVER_CAT, assignment will never be possible for all jobs of that category
 
1507
*
 
1508
*  NOTES
 
1509
*******************************************************************************/
 
1510
dispatch_t sge_queue_match_static(lListElem *queue, lListElem *job, const lListElem *pe, 
 
1511
                                  const lListElem *ckpt, lList *centry_list, lList *acl_list,
 
1512
                                  lList *hgrp_list, lList *ar_list) 
 
1513
{
 
1514
   u_long32 job_id;
 
1515
   u_long32 ar_id;
 
1516
   lList *projects;
 
1517
   lListElem *ar_ep;
 
1518
   const char *project;
 
1519
   const lList *hard_queue_list, *master_hard_queue_list;
 
1520
   const char *qinstance_name = lGetString(queue, QU_full_name);
 
1521
   bool could_be_master = false;
 
1522
 
 
1523
   DENTER(TOP_LAYER, "sge_queue_match_static");
 
1524
 
 
1525
   /* check if queue was reserved for AR job */
 
1526
   ar_id = lGetUlong(job, JB_ar);
 
1527
   ar_ep = lGetElemUlong(ar_list, AR_id, ar_id);
 
1528
 
 
1529
   if (ar_ep != NULL) {
 
1530
      DPRINTF(("searching for queue %s\n", qinstance_name));
 
1531
 
 
1532
      if (lGetSubStr(ar_ep, QU_full_name, qinstance_name, AR_reserved_queues) == NULL) {
 
1533
         schedd_mes_add_global(SCHEDD_INFO_QNOTARRESERVED_SI, qinstance_name, ar_id);
 
1534
         DRETURN(DISPATCH_NEVER_CAT);
 
1535
      }
 
1536
   } else {
 
1537
      /* this is not advance reservation job, we have to drop queues in orphaned state */
 
1538
      if (lGetUlong(queue, QU_state) == QI_ORPHANED) {
 
1539
         schedd_mes_add_global(SCHEDD_INFO_QUEUENOTAVAIL_, qinstance_name);
 
1540
         DRETURN(DISPATCH_NEVER_CAT);
 
1541
      }
 
1542
   }
 
1543
 
 
1544
   job_id = lGetUlong(job, JB_job_number);
 
1545
   /* check if job owner has access rights to the queue */
 
1546
   if (!sge_has_access(lGetString(job, JB_owner), lGetString(job, JB_group), queue, acl_list)) {
 
1547
      DPRINTF(("Job %d has no permission for queue %s\n", (int)job_id, qinstance_name));
 
1548
      schedd_mes_add(job_id, SCHEDD_INFO_HASNOPERMISSION_SS, "queue", qinstance_name);
 
1549
      DRETURN(DISPATCH_NEVER_CAT);
 
1550
   }
 
1551
 
 
1552
   /* check if job can run in queue based on project */
 
1553
   if ((projects = lGetList(queue, QU_projects))) {
 
1554
      if ((!(project = lGetString(job, JB_project)))) {
 
1555
         schedd_mes_add(job_id, SCHEDD_INFO_HASNOPRJ_S,
 
1556
            "queue", qinstance_name);
 
1557
         DRETURN(DISPATCH_NEVER_CAT);
 
1558
      }
 
1559
      if ((!prj_list_locate(projects, project))) {
 
1560
         schedd_mes_add(job_id, SCHEDD_INFO_HASINCORRECTPRJ_SSS,
 
1561
            project, "queue", qinstance_name);
 
1562
         DRETURN(DISPATCH_NEVER_CAT);
 
1563
      }
 
1564
   }
 
1565
 
 
1566
   /* check if job can run in queue based on excluded projects */
 
1567
   if ((projects = lGetList(queue, QU_xprojects))) {
 
1568
      if (((project = lGetString(job, JB_project)) &&
 
1569
           prj_list_locate(projects, project))) {
 
1570
         schedd_mes_add(job_id, SCHEDD_INFO_EXCLPRJ_SSS,
 
1571
            project, "queue", qinstance_name);
 
1572
         DRETURN(DISPATCH_NEVER_CAT);
 
1573
      }
 
1574
   }
 
1575
 
 
1576
   hard_queue_list = lGetList(job, JB_hard_queue_list);
 
1577
   master_hard_queue_list = lGetList(job, JB_master_hard_queue_list);
 
1578
   if (hard_queue_list || master_hard_queue_list) {
 
1579
      if (!centry_list_are_queues_requestable(centry_list)) {
 
1580
         schedd_mes_add(job_id, SCHEDD_INFO_QUEUENOTREQUESTABLE_S,
 
1581
            qinstance_name);
 
1582
         DRETURN(DISPATCH_NEVER_CAT);
 
1583
      }
 
1584
   }
 
1585
 
 
1586
   /* 
 
1587
    * is this queue a candidate for being the master queue? 
 
1588
    */
 
1589
   if (master_hard_queue_list) {
 
1590
      bool is_in_list = true;
 
1591
      if (qref_list_cq_rejected(master_hard_queue_list, lGetString(queue, QU_qname),
 
1592
                     lGetHost(queue, QU_qhostname), hgrp_list))
 
1593
         is_in_list = false;
 
1594
 
 
1595
      /*
 
1596
       * Tag queue
 
1597
       */
 
1598
      lSetUlong(queue, QU_tagged4schedule, is_in_list ? 1 : 0);
 
1599
      if (!is_in_list) {
 
1600
         DPRINTF(("Queue \"%s\" is not contained in the master hard "
 
1601
                  "queue list (-masterq) that was requested by job %d\n",
 
1602
                  qinstance_name, (int) job_id));
 
1603
      } else {
 
1604
         could_be_master = true;
 
1605
      }
 
1606
   } else {
 
1607
      lSetUlong(queue, QU_tagged4schedule, 0);
 
1608
   }
 
1609
      
 
1610
 
 
1611
   /* 
 
1612
    * is queue contained in hard queue list ? 
 
1613
    */
 
1614
   if (hard_queue_list) {
 
1615
      if ((could_be_master == false) && qref_list_cq_rejected(hard_queue_list, lGetString(queue, QU_qname),
 
1616
                     lGetHost(queue, QU_qhostname), hgrp_list)) {
 
1617
         DPRINTF(("Queue \"%s\" is not contained in the hard "
 
1618
                  "queue list (-q) that was requested by job %d\n",
 
1619
                  qinstance_name, (int) job_id));
 
1620
         schedd_mes_add(job_id, SCHEDD_INFO_NOTINHARDQUEUELST_S,
 
1621
                        qinstance_name);
 
1622
         DRETURN(DISPATCH_NEVER_CAT);
 
1623
      } 
 
1624
   }
 
1625
 
 
1626
   /*
 
1627
   ** different checks for different job types:
 
1628
   */
 
1629
 
 
1630
   if (pe) { /* parallel job */
 
1631
      if (!qinstance_is_parallel_queue(queue)) {
 
1632
         DPRINTF(("Queue \"%s\" is not a parallel queue as requested by " 
 
1633
                  "job %d\n", qinstance_name, (int)job_id));
 
1634
         schedd_mes_add(job_id, SCHEDD_INFO_NOTPARALLELQUEUE_S, qinstance_name);
 
1635
         DRETURN(DISPATCH_NEVER_CAT);
 
1636
      }
 
1637
 
 
1638
      /*
 
1639
       * check if the requested PE is named in the PE reference list of Queue
 
1640
       */
 
1641
      if (!qinstance_is_pe_referenced(queue, pe)) {
 
1642
         DPRINTF(("Queue "SFQ" does not reference PE "SFQ"\n",
 
1643
                  qinstance_name, lGetString(pe, PE_name)));
 
1644
         schedd_mes_add(job_id, SCHEDD_INFO_NOTINQUEUELSTOFPE_SS,
 
1645
                        qinstance_name, lGetString(pe, PE_name));
 
1646
         DRETURN(DISPATCH_NEVER_CAT);
 
1647
      }
 
1648
   }
 
1649
 
 
1650
   if (ckpt) { /* ckpt job */
 
1651
      /* is it a ckpt queue ? */
 
1652
      if (!qinstance_is_checkpointing_queue(queue)) {
 
1653
         DPRINTF(("Queue \"%s\" is not a checkpointing queue as requested by "
 
1654
                  "job %d\n", qinstance_name, (int)job_id));
 
1655
         schedd_mes_add(job_id, SCHEDD_INFO_NOTACKPTQUEUE_SS, qinstance_name);
 
1656
         DRETURN(DISPATCH_NEVER_CAT);
 
1657
      }
 
1658
 
 
1659
      /*
 
1660
       * check if the requested CKPT is named in the CKPT ref list of Queue
 
1661
       */
 
1662
      if (!qinstance_is_ckpt_referenced(queue, ckpt)) {
 
1663
         DPRINTF(("Queue \"%s\" does not reference checkpointing object "SFQ
 
1664
                  "\n", qinstance_name, lGetString(ckpt, CK_name)));
 
1665
         schedd_mes_add(job_id, SCHEDD_INFO_NOTINQUEUELSTOFCKPT_SS,  
 
1666
                        qinstance_name, lGetString(ckpt, CK_name));
 
1667
         DRETURN(DISPATCH_NEVER_CAT);
 
1668
      }
 
1669
   }   
 
1670
 
 
1671
   /* to be activated as soon as immediate jobs are available */
 
1672
   if (JOB_TYPE_IS_IMMEDIATE(lGetUlong(job, JB_type))) { 
 
1673
      if (!qinstance_is_interactive_queue(queue)) {
 
1674
         DPRINTF(("Queue \"%s\" is not an interactive queue as requested by "
 
1675
                  "job %d\n", qinstance_name, (int)job_id));
 
1676
         schedd_mes_add(job_id, SCHEDD_INFO_QUEUENOTINTERACTIVE_S, qinstance_name);
 
1677
         DRETURN(DISPATCH_NEVER_CAT);
 
1678
      } 
 
1679
   }
 
1680
 
 
1681
   if (!pe && !ckpt && !JOB_TYPE_IS_IMMEDIATE(lGetUlong(job, JB_type))) { /* serial (batch) job */
 
1682
      /* is it a batch or transfer queue */
 
1683
      if (!qinstance_is_batch_queue(queue)) {
 
1684
         DPRINTF(("Queue \"%s\" is not a batch queue as "
 
1685
                  "requested by job %d\n", qinstance_name, (int)job_id));
 
1686
         schedd_mes_add(job_id, SCHEDD_INFO_NOTASERIALQUEUE_S, qinstance_name);
 
1687
         DRETURN(DISPATCH_NEVER_CAT);
 
1688
      }
 
1689
   }
 
1690
 
 
1691
   if (ckpt && !pe && lGetString(job, JB_script_file) &&
 
1692
       qinstance_is_parallel_queue(queue) && !qinstance_is_batch_queue(queue)) {
 
1693
      DPRINTF(("Queue \"%s\" is not a serial queue as "
 
1694
               "requested by job %d\n", qinstance_name, (int)job_id));
 
1695
      schedd_mes_add(job_id, SCHEDD_INFO_NOTPARALLELJOB_S, qinstance_name);
 
1696
      DRETURN(DISPATCH_NEVER_CAT);
 
1697
   }
 
1698
 
 
1699
   if (job_is_forced_centry_missing(job, centry_list, queue)) {
 
1700
      DRETURN(DISPATCH_NEVER_CAT);
 
1701
   }
 
1702
 
 
1703
   DRETURN(DISPATCH_OK);
 
1704
}
 
1705
 
 
1706
static bool 
 
1707
job_is_forced_centry_missing(const lListElem *job, 
 
1708
                             const lList *master_centry_list, 
 
1709
                             const lListElem *queue_or_host)
 
1710
{
 
1711
   bool ret = false;
 
1712
   lListElem *centry;
 
1713
 
 
1714
   DENTER(TOP_LAYER, "job_is_forced_centry_missing");
 
1715
   if (job != NULL && master_centry_list != NULL && queue_or_host != NULL) {
 
1716
      lList *res_list = lGetList(job, JB_hard_resource_list);  
 
1717
 
 
1718
      for_each(centry, master_centry_list) {
 
1719
         const char *name = lGetString(centry, CE_name);
 
1720
         bool is_requ = is_requested(res_list, name);
 
1721
         bool is_forced = lGetUlong(centry, CE_requestable) == REQU_FORCED ? true : false;
 
1722
         const char *object_name = NULL;
 
1723
         bool is_qinstance = object_has_type(queue_or_host, QU_Type);
 
1724
         bool is_host = object_has_type(queue_or_host, EH_Type);
 
1725
 
 
1726
         if (is_forced) {
 
1727
            if (is_qinstance) {
 
1728
               is_forced = qinstance_is_centry_a_complex_value(queue_or_host, centry);
 
1729
               object_name = lGetString(queue_or_host, QU_full_name);
 
1730
            } else if (is_host) {
 
1731
               is_forced = host_is_centry_a_complex_value(queue_or_host, centry);
 
1732
               object_name = lGetHost(queue_or_host, EH_name);
 
1733
            } else {
 
1734
               DTRACE;
 
1735
               is_forced = false;
 
1736
            }
 
1737
         }
 
1738
 
 
1739
         if (is_forced && !is_requ) {
 
1740
            u_long32 job_id = lGetUlong(job, JB_job_number);
 
1741
 
 
1742
            DPRINTF(("job "sge_u32" does not request 'forced' resource "SFQ" of "
 
1743
                     SFN"\n", job_id, name, object_name));
 
1744
            if (is_qinstance) {
 
1745
               schedd_mes_add(job_id, SCHEDD_INFO_NOTREQFORCEDRES_SS, 
 
1746
                              name, object_name);
 
1747
            } else if (is_host) {
 
1748
               schedd_mes_add(job_id, SCHEDD_INFO_NOFORCEDRES_SS, 
 
1749
                              name, object_name);
 
1750
            }
 
1751
            ret = true;
 
1752
            break;
 
1753
         }
 
1754
      }
 
1755
   }
 
1756
   DRETURN(ret);
 
1757
}
 
1758
 
 
1759
/****** sge_select_queue/compute_soft_violations() ********************************
 
1760
*  NAME
 
1761
*     compute_soft_violations() -- counts the violations in the request for a given host or queue 
 
1762
*
 
1763
*  SYNOPSIS
 
1764
*     static int compute_soft_violations(lListElem *queue, int violation, lListElem *job,lList *load_attr, lList *config_attr,
 
1765
*                               lList *actual_attr, lList *centry_list, u_long32 layer, double lc_factor, u_long32 tag)
 
1766
*
 
1767
*  FUNCTION
 
1768
*     this function checks if the current resources can satisfy the requests. The resources come from the global host, a
 
1769
*     given host or the queue. The function returns the number of violations. 
 
1770
*
 
1771
*  INPUTS
 
1772
*     const sge_assignment_t *a - job info structure
 
1773
*     lListElem *queue     - should only be set, when one using this method on queue level 
 
1774
*     int violation        - the number of previous violations. This is needed to get a correct result on queue level. 
 
1775
*     lList *load_attr     - the load attributs, only when used on hosts or global 
 
1776
*     lList *config_attr   - a list of custom attributes  (CE_Type)
 
1777
*     lList *actual_attr   - a list of custom consumables, they contain the current usage of these attributes (RUE_Type)
 
1778
*     u_long32 layer       - the curent layer flag 
 
1779
*     double lc_factor     - should be set, when load correction has to be done. 
 
1780
*     u_long32 tag         - the current layer tag. (GLOGAL_TAG, HOST_TAG, QUEUE_TAG) 
 
1781
*
 
1782
*  RESULT
 
1783
*     static int - the number of violations ( = (prev. violations) + (new violations in this run)). 
 
1784
*
 
1785
*******************************************************************************/
 
1786
static int 
 
1787
compute_soft_violations(const sge_assignment_t *a, lListElem *queue, int violation, lList *load_attr, lList *config_attr,
 
1788
                    lList *actual_attr, u_long32 layer, double lc_factor, u_long32 tag) 
 
1789
{
 
1790
   u_long32 job_id;
 
1791
   const char *queue_name = NULL;
 
1792
   dstring reason;
 
1793
   char reason_buf[1024 + 1];
 
1794
   unsigned int soft_violation = violation;
 
1795
   lList *soft_requests = NULL; 
 
1796
   lListElem *attr;
 
1797
   u_long32 start_time = DISPATCH_TIME_NOW; 
 
1798
 
 
1799
   DENTER(TOP_LAYER, "compute_soft_violations");
 
1800
 
 
1801
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
1802
 
 
1803
   soft_requests = lGetList(a->job, JB_soft_resource_list);
 
1804
   clear_resource_tags(soft_requests, tag);
 
1805
 
 
1806
   job_id = a->job_id;
 
1807
   if (queue) {
 
1808
      queue_name = lGetString(queue, QU_full_name);
 
1809
   }   
 
1810
 
 
1811
   /* count number of soft violations for _one_ slot of this job */
 
1812
 
 
1813
   for_each (attr, soft_requests) {
 
1814
      switch (ri_time_by_slots(a, attr, load_attr, config_attr, actual_attr, queue,
 
1815
                      &reason, false, 1, layer, lc_factor, &start_time, queue_name?queue_name:"no queue")) {
 
1816
            /* no match */
 
1817
            case DISPATCH_NEVER_CAT:   
 
1818
               soft_violation++;
 
1819
               break;
 
1820
            /* element not found */
 
1821
            case DISPATCH_MISSING_ATTR:
 
1822
            case DISPATCH_NOT_AT_TIME:
 
1823
               if (tag == QUEUE_TAG && lGetUlong(attr, CE_tagged) == NO_TAG) {
 
1824
                  soft_violation++;
 
1825
               }               
 
1826
               break;
 
1827
            /* everything is fine */
 
1828
            default: 
 
1829
               if (lGetUlong(attr, CE_tagged) < tag)
 
1830
                  lSetUlong(attr, CE_tagged, tag);
 
1831
      }
 
1832
   }
 
1833
 
 
1834
   if (queue) {
 
1835
      DPRINTF(("queue %s does not fulfill soft %d requests (first: %s)\n", 
 
1836
         queue_name, soft_violation, reason_buf));
 
1837
 
 
1838
      /* 
 
1839
       * check whether queue fulfills soft queue request of the job (-q) 
 
1840
       */
 
1841
      if (lGetList(a->job, JB_soft_queue_list)) {
 
1842
         lList *qref_list = lGetList(a->job, JB_soft_queue_list);
 
1843
         lListElem *qr;
 
1844
         const char *qinstance_name = NULL;
 
1845
 
 
1846
         qinstance_name = lGetString(queue, QU_full_name);
 
1847
 
 
1848
         for_each (qr, qref_list) {
 
1849
            if (qref_cq_rejected(lGetString(qr, QR_name), lGetString(queue, QU_qname),
 
1850
                lGetHost(queue, QU_qhostname), a->hgrp_list)) {
 
1851
               DPRINTF(("Queue \"%s\" is not contained in the soft "
 
1852
                        "queue list (-q) that was requested by job %d\n",
 
1853
                        qinstance_name, (int) job_id));
 
1854
               soft_violation++;
 
1855
            }
 
1856
         }
 
1857
      }
 
1858
 
 
1859
      /* store number of soft violations in queue */
 
1860
      lSetUlong(queue, QU_soft_violation, soft_violation);
 
1861
   }
 
1862
 
 
1863
   DRETURN(soft_violation);
 
1864
}
 
1865
 
 
1866
/****** sge_select_queue/sge_host_match_static() ********************************
 
1867
*  NAME
 
1868
*     sge_host_match_static() -- Static test whether job fits to host
 
1869
*
 
1870
*  SYNOPSIS
 
1871
*     static int sge_host_match_static(lListElem *job, lListElem *ja_task, 
 
1872
*     lListElem *host, lList *centry_list, lList *acl_list) 
 
1873
*
 
1874
*  FUNCTION
 
1875
*
 
1876
*  INPUTS
 
1877
*     lListElem *job     - ??? 
 
1878
*     lListElem *ja_task - ??? 
 
1879
*     lListElem *host    - ??? 
 
1880
*     lList *centry_list - ??? 
 
1881
*     lList *acl_list    - ??? 
 
1882
*
 
1883
*  RESULT
 
1884
*     int - 0 ok 
 
1885
*          -1 assignment will never be possible for all jobs of that category
 
1886
*          -2 assignment will never be possible for that particular job
 
1887
*******************************************************************************/
 
1888
dispatch_t
 
1889
sge_host_match_static(lListElem *job, lListElem *ja_task, lListElem *host, 
 
1890
                      lList *centry_list, lList *acl_list) 
 
1891
{
 
1892
   lList *projects;
 
1893
   const char *project;
 
1894
   u_long32 job_id;
 
1895
   const char *eh_name;
 
1896
 
 
1897
   DENTER(TOP_LAYER, "sge_host_match_static");
 
1898
 
 
1899
   if (!host) {
 
1900
      DRETURN(DISPATCH_OK);
 
1901
   }
 
1902
 
 
1903
   job_id = lGetUlong(job, JB_job_number);
 
1904
   eh_name = lGetHost(host, EH_name);
 
1905
 
 
1906
   /* check if job owner has access rights to the host */
 
1907
   if (!sge_has_access_(lGetString(job, JB_owner),
 
1908
         lGetString(job, JB_group), lGetList(host, EH_acl),
 
1909
         lGetList(host, EH_xacl), acl_list)) {
 
1910
      DPRINTF(("Job %d has no permission for host %s\n",
 
1911
               (int)job_id, eh_name));
 
1912
      schedd_mes_add(job_id, SCHEDD_INFO_HASNOPERMISSION_SS,
 
1913
         "host", eh_name);
 
1914
      DRETURN(DISPATCH_NEVER_CAT);
 
1915
   }
 
1916
 
 
1917
   /* check if job can run on host based on required projects */
 
1918
   if ((projects = lGetList(host, EH_prj))) {
 
1919
   
 
1920
      if ((!(project = lGetString(job, JB_project)))) {
 
1921
         schedd_mes_add(job_id, SCHEDD_INFO_HASNOPRJ_S,
 
1922
            "host", eh_name);
 
1923
         DRETURN(DISPATCH_NEVER_CAT);
 
1924
      }
 
1925
 
 
1926
      if ((!prj_list_locate(projects, project))) {
 
1927
         schedd_mes_add(job_id, SCHEDD_INFO_HASINCORRECTPRJ_SSS,
 
1928
            project, "host", eh_name);
 
1929
         DRETURN(DISPATCH_NEVER_CAT);
 
1930
      }
 
1931
   }
 
1932
 
 
1933
   /* check if job can run on host based on excluded projects */
 
1934
   if ((projects = lGetList(host, EH_xprj))) {
 
1935
      if (((project = lGetString(job, JB_project)) &&
 
1936
           prj_list_locate(projects, project))) {
 
1937
         schedd_mes_add(job_id, SCHEDD_INFO_EXCLPRJ_SSS,
 
1938
            project, "host", eh_name);
 
1939
         DRETURN(DISPATCH_NEVER_CAT);
 
1940
      }
 
1941
   }
 
1942
 
 
1943
   if (job_is_forced_centry_missing(job, centry_list, host)) {
 
1944
      DRETURN(DISPATCH_NEVER_CAT);
 
1945
   }
 
1946
 
 
1947
   /* RU: */
 
1948
   /* 
 
1949
   ** check if job can run on host based on the list of jids/taskids
 
1950
   ** contained in the reschedule_unknown-list
 
1951
   */
 
1952
   if (ja_task) {
 
1953
      lListElem *ruep;
 
1954
      lList *rulp;
 
1955
      u_long32 task_id;
 
1956
 
 
1957
      task_id = lGetUlong(ja_task, JAT_task_number);
 
1958
      rulp = lGetList(host, EH_reschedule_unknown_list);
 
1959
 
 
1960
      for_each(ruep, rulp) {
 
1961
         if (lGetUlong(ruep, RU_job_number) == job_id 
 
1962
             && lGetUlong(ruep, RU_task_number) == task_id) {
 
1963
            DPRINTF(("RU: Job "sge_u32"."sge_u32" Host "SFN"\n", job_id,
 
1964
               task_id, eh_name));
 
1965
            schedd_mes_add(job_id, SCHEDD_INFO_CLEANUPNECESSARY_S,
 
1966
               eh_name);
 
1967
            DRETURN(DISPATCH_NEVER_JOB);
 
1968
         }
 
1969
      }
 
1970
   } 
 
1971
 
 
1972
   DRETURN(DISPATCH_OK);
 
1973
}
 
1974
 
 
1975
/****** sge_select_queue/is_requested() ****************************************
 
1976
*  NAME
 
1977
*     is_requested() -- Returns true if specified resource is requested. 
 
1978
*
 
1979
*  SYNOPSIS
 
1980
*     bool is_requested(lList *req, const char *attr) 
 
1981
*
 
1982
*  FUNCTION
 
1983
*     Returns true if specified resource is requested. Both long name
 
1984
*     and shortcut name are checked.
 
1985
*
 
1986
*  INPUTS
 
1987
*     lList *req       - The request list (CE_Type)
 
1988
*     const char *attr - The resource name.
 
1989
*
 
1990
*  RESULT
 
1991
*     bool - true if requested, otherwise false 
 
1992
*
 
1993
*  NOTES
 
1994
*     MT-NOTE: is_requested() is MT safe 
 
1995
*******************************************************************************/
 
1996
bool is_requested(lList *req, const char *attr) 
 
1997
{
 
1998
   if (lGetElemStr(req, CE_name, attr) ||
 
1999
       lGetElemStr(req, CE_shortcut , attr)) {
 
2000
      return true;
 
2001
   }
 
2002
 
 
2003
   return false;
 
2004
}
 
2005
 
 
2006
static int load_check_alarm(char *reason, const char *name, const char *load_value, 
 
2007
                                const char *limit_value, u_long32 relop, 
 
2008
                                u_long32 type, lListElem *hep, 
 
2009
                                lListElem *hlep, double lc_host, 
 
2010
                                double lc_global, const lList *load_adjustments, int load_is_value) 
 
2011
{
 
2012
   lListElem *job_load;
 
2013
   double limit, load;
 
2014
   int match;
 
2015
#define STR_LC_DIAGNOSIS 1024   
 
2016
   char lc_diagnosis1[STR_LC_DIAGNOSIS], lc_diagnosis2[STR_LC_DIAGNOSIS];
 
2017
   
 
2018
   DENTER(TOP_LAYER, "load_check_alarm");
 
2019
 
 
2020
   switch (type) {
 
2021
      case TYPE_INT:
 
2022
      case TYPE_TIM:
 
2023
      case TYPE_MEM:
 
2024
      case TYPE_BOO:
 
2025
      case TYPE_DOUBLE:
 
2026
         if (!parse_ulong_val(&load, NULL, type, load_value, NULL, 0)) {
 
2027
            if (reason)
 
2028
               sprintf(reason, MSG_SCHEDD_WHYEXCEEDINVALIDLOAD_SS, load_value, name);
 
2029
            DRETURN(1);
 
2030
         }
 
2031
         if (!parse_ulong_val(&limit, NULL, type, limit_value, NULL, 0)) {
 
2032
            if (reason)
 
2033
               sprintf(reason, MSG_SCHEDD_WHYEXCEEDINVALIDTHRESHOLD_SS, name, limit_value);
 
2034
            DRETURN(1);
 
2035
         }
 
2036
         if (load_is_value) { /* we got no load - this is just the complex value */
 
2037
            sge_strlcpy(lc_diagnosis2, MSG_SCHEDD_LCDIAGNOLOAD, STR_LC_DIAGNOSIS);
 
2038
         } else if (((hlep && lc_host) || lc_global) &&
 
2039
            (job_load = lGetElemStr(load_adjustments, CE_name, name))) { /* load correction */
 
2040
            const char *load_correction_str;
 
2041
            double load_correction;
 
2042
 
 
2043
            load_correction_str = lGetString(job_load, CE_stringval);
 
2044
            if (!parse_ulong_val(&load_correction, NULL, type, load_correction_str, NULL, 0)) {
 
2045
               if (reason)
 
2046
                  sprintf(reason, MSG_SCHEDD_WHYEXCEEDINVALIDLOADADJUST_SS, name, load_correction_str);
 
2047
               DRETURN(1);
 
2048
            }
 
2049
 
 
2050
            if (hlep) {
 
2051
               int nproc;
 
2052
               load_correction *= lc_host;
 
2053
 
 
2054
               if ((nproc = load_np_value_adjustment(name, hep,  &load_correction)) > 0) {
 
2055
                  sprintf(lc_diagnosis1, MSG_SCHEDD_LCDIAGHOSTNP_SFI,
 
2056
                         load_correction_str, lc_host, nproc);
 
2057
               }
 
2058
               else {
 
2059
                  sprintf(lc_diagnosis1, MSG_SCHEDD_LCDIAGHOST_SF,
 
2060
                         load_correction_str, lc_host);
 
2061
               
 
2062
               }
 
2063
            
 
2064
            } 
 
2065
            else {
 
2066
               load_correction *= lc_global;
 
2067
               sprintf(lc_diagnosis1, MSG_SCHEDD_LCDIAGGLOBAL_SF,
 
2068
                         load_correction_str, lc_global);
 
2069
            }
 
2070
            /* it depends on relop in complex config
 
2071
            whether load_correction is pos/neg */
 
2072
            switch (relop) {
 
2073
            case CMPLXGE_OP:
 
2074
            case CMPLXGT_OP:
 
2075
               load += load_correction;
 
2076
               sprintf(lc_diagnosis2, MSG_SCHEDD_LCDIAGPOSITIVE_SS, load_value, lc_diagnosis1);
 
2077
               break;
 
2078
 
 
2079
            case CMPLXNE_OP:
 
2080
            case CMPLXEQ_OP:
 
2081
            case CMPLXLT_OP:
 
2082
            case CMPLXLE_OP:
 
2083
            default:
 
2084
               load -= load_correction;
 
2085
               sprintf(lc_diagnosis2, MSG_SCHEDD_LCDIAGNEGATIVE_SS, load_value, lc_diagnosis1);
 
2086
               break;
 
2087
            }
 
2088
         } else  {
 
2089
            sge_strlcpy(lc_diagnosis2, MSG_SCHEDD_LCDIAGNONE, STR_LC_DIAGNOSIS);
 
2090
         }   
 
2091
 
 
2092
         /* is threshold exceeded ? */
 
2093
         if (resource_cmp(relop, load, limit)) {
 
2094
            if (reason) {
 
2095
               if (type == TYPE_BOO){
 
2096
                  sprintf(reason, MSG_SCHEDD_WHYEXCEEDBOOLVALUE_SSSSS,
 
2097
                        name, load?MSG_TRUE:MSG_FALSE, lc_diagnosis2, map_op2str(relop), limit_value);
 
2098
               }         
 
2099
               else {
 
2100
                  sprintf(reason, MSG_SCHEDD_WHYEXCEEDFLOATVALUE_SFSSS,
 
2101
                        name, load, lc_diagnosis2, map_op2str(relop), limit_value);
 
2102
               }         
 
2103
            }
 
2104
            DRETURN(1);
 
2105
         }
 
2106
         break;
 
2107
 
 
2108
      case TYPE_STR:
 
2109
      case TYPE_CSTR:
 
2110
      case TYPE_HOST:
 
2111
      case TYPE_RESTR:
 
2112
         match = string_base_cmp(type, limit_value, load_value);
 
2113
         if (!match) {
 
2114
            if (reason)
 
2115
               sprintf(reason, MSG_SCHEDD_WHYEXCEEDSTRINGVALUE_SSSS, name, load_value, map_op2str(relop), limit_value);
 
2116
            DRETURN(1);
 
2117
         }
 
2118
         break;
 
2119
      default:
 
2120
         if (reason)
 
2121
            sprintf(reason, MSG_SCHEDD_WHYEXCEEDCOMPLEXTYPE_S, name);
 
2122
         DRETURN(1);
 
2123
   }
 
2124
 
 
2125
   DRETURN(0);
 
2126
}
 
2127
 
 
2128
/****** sge_select_queue/load_np_value_adjustment() ****************************
 
2129
*  NAME
 
2130
*     load_np_value_adjustment() -- adjusts np load values for the number of processors
 
2131
*
 
2132
*  SYNOPSIS
 
2133
*     static int load_np_value_adjustment(const char* name, lListElem *hep, 
 
2134
*     double *load_correction) 
 
2135
*
 
2136
*  FUNCTION
 
2137
*     Tests the load value name for "np_*". If this pattern is found, it will
 
2138
*     retrieve the number of processors and adjusts the load_correction accordingly.
 
2139
*     If the pattern is not found, it does nothing and returns 0 for number of processors.
 
2140
*
 
2141
*  INPUTS
 
2142
*     const char* name        - load value name
 
2143
*     lListElem *hep          - host object 
 
2144
*     double *load_correction - current load_correction for further corrections
 
2145
*
 
2146
*  RESULT
 
2147
*     static int - number of processors, or 0 if it was called on a none np load value 
 
2148
*
 
2149
*  NOTES
 
2150
*     MT-NOTE: load_np_value_adjustment() is MT safe 
 
2151
*
 
2152
*******************************************************************************/
 
2153
static int load_np_value_adjustment(const char* name, lListElem *hep, double *load_correction) {
 
2154
 
 
2155
   int nproc = 1;
 
2156
   if (!strncmp(name, "np_", 3)) {
 
2157
      int nproc = 1;
 
2158
      lListElem *ep_nproc;
 
2159
 
 
2160
      if ((ep_nproc = lGetSubStr(hep, HL_name, LOAD_ATTR_NUM_PROC, EH_load_list))) {
 
2161
         const char* cp = lGetString(ep_nproc, HL_value);
 
2162
         if (cp) {
 
2163
            nproc = atoi(cp);
 
2164
      
 
2165
            if (nproc > 1) {
 
2166
               *load_correction /= nproc;
 
2167
            }
 
2168
         }
 
2169
      }
 
2170
   } 
 
2171
   else {
 
2172
      nproc = 0;          
 
2173
   }
 
2174
  
 
2175
   return nproc;
 
2176
}
 
2177
 
 
2178
static int resource_cmp(u_long32 relop, double req, double src_dl) 
 
2179
{
 
2180
   int match;
 
2181
 
 
2182
   switch(relop) { 
 
2183
   case CMPLXEQ_OP :
 
2184
      match = ( req==src_dl);
 
2185
      break;
 
2186
   case CMPLXLE_OP :
 
2187
      match = ( req<=src_dl);
 
2188
      break;
 
2189
   case CMPLXLT_OP :
 
2190
      match = ( req<src_dl);
 
2191
      break;
 
2192
   case CMPLXGT_OP :
 
2193
      match = ( req>src_dl);
 
2194
      break;
 
2195
   case CMPLXGE_OP :
 
2196
      match = ( req>=src_dl);
 
2197
      break;
 
2198
   case CMPLXNE_OP :
 
2199
      match = ( req!=src_dl);
 
2200
      break;
 
2201
   default:
 
2202
      match = 0; /* default -> no match */
 
2203
   }
 
2204
 
 
2205
   return match;      
 
2206
}
 
2207
 
 
2208
/* ----------------------------------------
 
2209
 
 
2210
   sge_load_alarm() 
 
2211
 
 
2212
   checks given threshold of the queue;
 
2213
   centry_list and exechost_list get used
 
2214
   therefore
 
2215
 
 
2216
   returns boolean:
 
2217
      1 yes, the threshold is exceeded
 
2218
      0 no
 
2219
*/
 
2220
 
 
2221
int 
 
2222
sge_load_alarm(char *reason, lListElem *qep, lList *threshold, 
 
2223
               const lList *exechost_list, const lList *centry_list, 
 
2224
               const lList *load_adjustments, bool is_check_consumable) 
 
2225
{
 
2226
   lListElem *hep, *global_hep, *tep;
 
2227
   u_long32 ulc_factor; 
 
2228
   const char *load_value = NULL; 
 
2229
   const char *limit_value = NULL;
 
2230
   double lc_host = 0, lc_global = 0;
 
2231
   int load_is_value = 0;
 
2232
   
 
2233
   DENTER(TOP_LAYER, "sge_load_alarm");
 
2234
 
 
2235
   if (!threshold) { 
 
2236
      /* no threshold -> no alarm */
 
2237
      DRETURN(0);
 
2238
   }
 
2239
 
 
2240
   hep = host_list_locate(exechost_list, lGetHost(qep, QU_qhostname));
 
2241
 
 
2242
   if(!hep) { 
 
2243
      if (reason)
 
2244
         sprintf(reason, MSG_SCHEDD_WHYEXCEEDNOHOST_S, lGetHost(qep, QU_qhostname));
 
2245
      /* no host for queue -> ERROR */
 
2246
      DRETURN(1);
 
2247
   }
 
2248
 
 
2249
   if ((lGetPosViaElem(hep, EH_load_correction_factor, SGE_NO_ABORT) >= 0)
 
2250
       && (ulc_factor=lGetUlong(hep, EH_load_correction_factor))) {
 
2251
      lc_host = ((double)ulc_factor)/100;
 
2252
   }   
 
2253
 
 
2254
   if ((global_hep = host_list_locate(exechost_list, SGE_GLOBAL_NAME)) != NULL) {
 
2255
      if ((lGetPosViaElem(global_hep, EH_load_correction_factor, SGE_NO_ABORT) >= 0)
 
2256
          && (ulc_factor=lGetUlong(global_hep, EH_load_correction_factor)))
 
2257
         lc_global = ((double)ulc_factor)/100;
 
2258
   }
 
2259
 
 
2260
   for_each (tep, threshold) {
 
2261
      lListElem *hlep = NULL, *glep = NULL, *queue_ep = NULL, *cep  = NULL;
 
2262
      bool need_free_cep = false;
 
2263
      const char *name;
 
2264
      u_long32 relop, type;
 
2265
 
 
2266
      name = lGetString(tep, CE_name);
 
2267
      /* complex attriute definition */
 
2268
 
 
2269
      if (!(cep = centry_list_locate(centry_list, name))) { 
 
2270
         if (reason)
 
2271
            sprintf(reason, MSG_SCHEDD_WHYEXCEEDNOCOMPLEX_S, name);
 
2272
         DRETURN(1);
 
2273
      }
 
2274
      if (!is_check_consumable && lGetBool(cep, CE_consumable)) { 
 
2275
         continue;
 
2276
      }
 
2277
 
 
2278
      if (hep != NULL) {
 
2279
         hlep = lGetSubStr(hep, HL_name, name, EH_load_list);
 
2280
      }   
 
2281
 
 
2282
      if (!lGetBool(cep, CE_consumable)) { 
 
2283
         if (hlep != NULL) {
 
2284
            load_value = lGetString(hlep, HL_value);
 
2285
            load_is_value = 0;
 
2286
         } else if ((global_hep != NULL) &&
 
2287
                  ((glep = lGetSubStr(global_hep, HL_name, name, EH_load_list)) != NULL)) {
 
2288
               load_value = lGetString(glep, HL_value);
 
2289
               load_is_value = 0;
 
2290
         } 
 
2291
         else {
 
2292
            queue_ep = lGetSubStr(qep, CE_name, name, QU_consumable_config_list);
 
2293
            if (queue_ep != NULL) {
 
2294
               load_value = lGetString(queue_ep, CE_stringval);
 
2295
               load_is_value = 1;
 
2296
            } else { 
 
2297
               if (reason) {
 
2298
                  sprintf(reason, MSG_SCHEDD_NOVALUEFORATTR_S, name);
 
2299
               }
 
2300
               DRETURN(1);
 
2301
            }
 
2302
         }      
 
2303
      }
 
2304
      else {
 
2305
         /* load thesholds... */
 
2306
         if ((cep = get_attribute_by_name(global_hep, hep, qep, name, centry_list, DISPATCH_TIME_NOW, 0)) == NULL ) {
 
2307
            if (reason)
 
2308
               sprintf(reason, MSG_SCHEDD_WHYEXCEEDNOCOMPLEX_S, name);
 
2309
            DRETURN(1);
 
2310
         }
 
2311
         need_free_cep = true;
 
2312
     
 
2313
         load_value = lGetString(cep, CE_pj_stringval);
 
2314
         load_is_value = (lGetUlong(cep, CE_pj_dominant) & DOMINANT_TYPE_MASK) != DOMINANT_TYPE_CLOAD; 
 
2315
      }
 
2316
 
 
2317
      relop = lGetUlong(cep, CE_relop);
 
2318
      limit_value = lGetString(tep, CE_stringval);
 
2319
      type = lGetUlong(cep, CE_valtype);
 
2320
 
 
2321
      if(load_check_alarm(reason, name, load_value, limit_value, relop, 
 
2322
                              type, hep, hlep, lc_host, lc_global, 
 
2323
                              load_adjustments, load_is_value)) {
 
2324
         if (need_free_cep) {
 
2325
            lFreeElem(&cep);
 
2326
         }
 
2327
         DRETURN(1);
 
2328
      }   
 
2329
      if (need_free_cep) {
 
2330
         lFreeElem(&cep);
 
2331
      }
 
2332
   } 
 
2333
 
 
2334
   DRETURN(0);
 
2335
}
 
2336
 
 
2337
/* ----------------------------------------
 
2338
 
 
2339
   sge_load_alarm_reasons() 
 
2340
 
 
2341
   checks given threshold of the queue;
 
2342
   centry_list and exechost_list get used
 
2343
   therefore
 
2344
 
 
2345
   fills and returns string buffer containing reasons for alarm states
 
2346
*/
 
2347
 
 
2348
char *sge_load_alarm_reason(lListElem *qep, lList *threshold, 
 
2349
                            const lList *exechost_list, const lList *centry_list, 
 
2350
                            char *reason, int reason_size, 
 
2351
                            const char *threshold_type) 
 
2352
{
 
2353
   DENTER(TOP_LAYER, "sge_load_alarm_reason");
 
2354
 
 
2355
   *reason = 0;
 
2356
 
 
2357
   /* no threshold -> no alarm */
 
2358
   if (threshold != NULL) {
 
2359
      lList *rlp = NULL;
 
2360
      lListElem *tep;
 
2361
      bool first = true;
 
2362
 
 
2363
      /* get actual complex values for queue */
 
2364
      queue_complexes2scheduler(&rlp, qep, exechost_list, centry_list);
 
2365
 
 
2366
      /* check all thresholds */
 
2367
      for_each (tep, threshold) {
 
2368
         const char *name;             /* complex attrib name */
 
2369
         lListElem *cep;               /* actual complex attribute */
 
2370
         char dom_str[5];              /* dominance as string */
 
2371
         u_long32 dom_val;             /* dominance as u_long */
 
2372
         char buffer[MAX_STRING_SIZE]; /* buffer for one line */
 
2373
         const char *load_value;       /* actual load value */
 
2374
         const char *limit_value;      /* limit defined by threshold */
 
2375
 
 
2376
         name = lGetString(tep, CE_name);
 
2377
 
 
2378
         if ( first == true ) {
 
2379
            first = false;
 
2380
         } else {
 
2381
            strncat(reason, "\n\t", reason_size);
 
2382
         }
 
2383
 
 
2384
         /* find actual complex attribute */
 
2385
         if ((cep = lGetElemStr(rlp, CE_name, name)) == NULL) {
 
2386
            /* no complex attribute for threshold -> ERROR */
 
2387
            if (qinstance_state_is_unknown(qep)) {
 
2388
               snprintf(buffer, MAX_STRING_SIZE, MSG_QINSTANCE_VALUEMISSINGMASTERDOWN_S, name);
 
2389
            } else {
 
2390
               snprintf(buffer, MAX_STRING_SIZE, MSG_SCHEDD_NOCOMPLEXATTRIBUTEFORTHRESHOLD_S, name);
 
2391
            }
 
2392
            strncat(reason, buffer, reason_size);
 
2393
            continue;
 
2394
         }
 
2395
 
 
2396
         limit_value = lGetString(tep, CE_stringval);
 
2397
 
 
2398
         if (!(lGetUlong(cep, CE_pj_dominant) & DOMINANT_TYPE_VALUE)) {
 
2399
            dom_val = lGetUlong(cep, CE_pj_dominant);
 
2400
            load_value = lGetString(cep, CE_pj_stringval);
 
2401
         } else {
 
2402
            dom_val = lGetUlong(cep, CE_dominant);
 
2403
            load_value = lGetString(cep, CE_stringval);
 
2404
         }
 
2405
 
 
2406
         monitor_dominance(dom_str, dom_val);
 
2407
 
 
2408
         snprintf(buffer, MAX_STRING_SIZE, "alarm %s:%s=%s %s-threshold=%s",
 
2409
                 dom_str,
 
2410
                 name, 
 
2411
                 load_value,
 
2412
                 threshold_type,
 
2413
                 limit_value
 
2414
                );
 
2415
 
 
2416
         strncat(reason, buffer, reason_size);
 
2417
      }
 
2418
 
 
2419
      lFreeList(&rlp);
 
2420
   }   
 
2421
 
 
2422
   DRETURN(reason);
 
2423
}
 
2424
 
 
2425
/* ----------------------------------------
 
2426
 
 
2427
   sge_split_queue_load()
 
2428
 
 
2429
   splits the incoming queue list (1st arg) into an unloaded and
 
2430
   overloaded (2nd arg) list according to the load values contained in
 
2431
   the execution host list (3rd arg) and with respect to the definitions
 
2432
   in the complex list (4th arg).
 
2433
 
 
2434
   temporarily sets QU_tagged4schedule but sets it to 0 on exit.
 
2435
 
 
2436
   returns:
 
2437
      0 successful
 
2438
     -1 errors in functions called by sge_split_queue_load
 
2439
 
 
2440
*/
 
2441
int sge_split_queue_load(
 
2442
lList **unloaded,               /* QU_Type */
 
2443
lList **overloaded,             /* QU_Type */
 
2444
lList *exechost_list,           /* EH_Type */
 
2445
lList *centry_list,             /* CE_Type */
 
2446
const lList *load_adjustments,  /* CE_Type */
 
2447
lList *granted,                 /* JG_Type */
 
2448
bool  is_consumable_load_alarm, /* is true, when the consumable evaluation 
 
2449
                                   set a load alarm */
 
2450
bool is_comprehensive,          /* do the load evaluation comprehensive (include consumables) */
 
2451
u_long32 ttype
 
2452
) {
 
2453
   lList *thresholds;
 
2454
   lCondition *where;
 
2455
   lListElem *qep;
 
2456
   int ret, load_alarm, nverified = 0;
 
2457
   char reason[2048];
 
2458
 
 
2459
   DENTER(TOP_LAYER, "sge_split_queue_load");
 
2460
 
 
2461
   /* a job has been dispatched recently,
 
2462
      but load correction is not in use at all */
 
2463
   if (granted && !load_adjustments && !is_consumable_load_alarm) {
 
2464
      DRETURN(0);
 
2465
   }
 
2466
 
 
2467
   if (!(granted && !load_adjustments)) { 
 
2468
 
 
2469
   /* tag those queues being overloaded */
 
2470
      for_each(qep, *unloaded) {
 
2471
         thresholds = lGetList(qep, ttype);
 
2472
         load_alarm = 0;
 
2473
 
 
2474
         /* do not verify load alarm anew if a job has been dispatched recently
 
2475
            but not to the host where this queue resides */
 
2476
         if (!granted || (granted && (sconf_get_global_load_correction() ||
 
2477
                              lGetElemHost(granted, JG_qhostname, lGetHost(qep, QU_qhostname))))) {
 
2478
            nverified++;
 
2479
 
 
2480
            if (sge_load_alarm(reason, qep, thresholds, exechost_list, centry_list, load_adjustments, is_comprehensive) != 0) {
 
2481
               load_alarm = 1;
 
2482
               if (ttype==QU_suspend_thresholds) {
 
2483
                  DPRINTF(("queue %s tagged to be in suspend alarm: %s\n", 
 
2484
                        lGetString(qep, QU_full_name), reason));
 
2485
                  schedd_mes_add_global(SCHEDD_INFO_QUEUEINALARM_SS, lGetString(qep, QU_full_name), reason);
 
2486
               } else {
 
2487
                  DPRINTF(("queue %s tagged to be overloaded: %s\n", 
 
2488
                        lGetString(qep, QU_full_name), reason));
 
2489
                  schedd_mes_add_global(SCHEDD_INFO_QUEUEOVERLOADED_SS, lGetString(qep, QU_full_name), reason);
 
2490
               }
 
2491
            }
 
2492
         }
 
2493
         if (load_alarm) {
 
2494
            lSetUlong(qep, QU_tagged4schedule, load_alarm);
 
2495
         }   
 
2496
      }
 
2497
   }
 
2498
 
 
2499
   DPRINTF(("verified threshold of %d queues\n", nverified));
 
2500
 
 
2501
   /* split queues in unloaded and overloaded lists */
 
2502
   where = lWhere("%T(%I == %u)", lGetListDescr(*unloaded), QU_tagged4schedule, 0);
 
2503
   ret = lSplit(unloaded, overloaded, "overloaded queues", where);
 
2504
   lFreeWhere(&where);
 
2505
 
 
2506
   if (overloaded) {
 
2507
      for_each(qep, *overloaded) { /* make sure QU_tagged4schedule is 0 on exit */
 
2508
         lSetUlong(qep, QU_tagged4schedule, 0);
 
2509
      }
 
2510
   }
 
2511
 
 
2512
   if (ret) {
 
2513
      DRETURN(-1);
 
2514
   }
 
2515
 
 
2516
   DRETURN(0);
 
2517
}
 
2518
 
 
2519
 
 
2520
/****** sge_select_queue/sge_split_queue_slots_free() **************************
 
2521
*  NAME
 
2522
*     sge_split_queue_slots_free() -- ??? 
 
2523
*
 
2524
*  SYNOPSIS
 
2525
*     int sge_split_queue_slots_free(lList **free, lList **full) 
 
2526
*
 
2527
*  FUNCTION
 
2528
*     Split queue list into queues with at least one slots and queues with 
 
2529
*     less than one free slot. The list optioally returned in full gets the
 
2530
*     QNOSLOTS queue instance state set.
 
2531
*
 
2532
*  INPUTS
 
2533
*     lList **free - Input queue instance list and return free slots.
 
2534
*     lList **full - If non-NULL the full queue instances get returned here.
 
2535
*
 
2536
*
 
2537
*  TODO: take a look into list hashing, not needed for temp list
 
2538
*
 
2539
*  RESULT
 
2540
*     int - 0 success 
 
2541
*          -1 error
 
2542
*******************************************************************************/
 
2543
int sge_split_queue_slots_free(lList **free, lList **full) 
 
2544
{
 
2545
   lList *full_queues = NULL;
 
2546
   lListElem *this = NULL;
 
2547
   lListElem *next = NULL;
 
2548
 
 
2549
   DENTER(TOP_LAYER, "sge_split_queue_nslots_free");
 
2550
 
 
2551
   if (free == NULL) {
 
2552
      DRETURN(-1);
 
2553
   }
 
2554
 
 
2555
   for (this=lFirst(*free); ((next=lNext(this))), this ; this = next) {
 
2556
      if (qinstance_slots_used(this) >= (int)lGetUlong(this, QU_job_slots)) {
 
2557
          
 
2558
         this = lDechainElem(*free, this);        
 
2559
          
 
2560
         if (!qinstance_state_is_full(this)) {
 
2561
            schedd_mes_add_global(SCHEDD_INFO_QUEUEFULL_, lGetString(this, QU_full_name));
 
2562
            qinstance_state_set_full(this, true);
 
2563
 
 
2564
            if (full_queues == NULL) { 
 
2565
               full_queues = lCreateListHash("full one", lGetListDescr(*free), false);
 
2566
            }
 
2567
            lAppendElem(full_queues, this);             
 
2568
         }   
 
2569
         else if (full != NULL) {
 
2570
            if (*full == NULL) {
 
2571
               *full = lCreateList("full one", lGetListDescr(*free));
 
2572
            }   
 
2573
            lAppendElem(*full, this);
 
2574
         } 
 
2575
         else {
 
2576
            lFreeElem(&this);
 
2577
         }   
 
2578
      }
 
2579
   }
 
2580
 
 
2581
   /* dump out the -tsm log and add the new queues to the disabled queue list */
 
2582
   if (full_queues) {
 
2583
      schedd_log_list(MSG_SCHEDD_LOGLIST_QUEUESFULLANDDROPPED , full_queues, QU_full_name);
 
2584
      if (full != NULL) {
 
2585
         if (*full == NULL) {
 
2586
            *full = full_queues;
 
2587
            full_queues = NULL;
 
2588
         }
 
2589
         else {
 
2590
            lAddList(*full, &full_queues);
 
2591
            full_queues = NULL;
 
2592
         }
 
2593
      }
 
2594
      else {
 
2595
         lFreeList(&full_queues);
 
2596
      }
 
2597
   }
 
2598
 
 
2599
   DRETURN(0);
 
2600
}
 
2601
 
 
2602
 
 
2603
/* ----------------------------------------
 
2604
 
 
2605
   sge_split_suspended()
 
2606
 
 
2607
   splits the incoming queue list (1st arg) into non suspended queues and
 
2608
   suspended queues (2nd arg) 
 
2609
 
 
2610
   returns:
 
2611
      0 successful
 
2612
     -1 error
 
2613
 
 
2614
*/
 
2615
int sge_split_suspended(
 
2616
lList **queue_list,        /* QU_Type */
 
2617
lList **suspended         /* QU_Type */
 
2618
) {
 
2619
   lCondition *where;
 
2620
   int ret;
 
2621
   lList *lp = NULL;
 
2622
 
 
2623
   DENTER(TOP_LAYER, "sge_split_suspended");
 
2624
 
 
2625
   if (!queue_list) {
 
2626
      DRETURN(-1);
 
2627
   }
 
2628
 
 
2629
   if (!suspended) {
 
2630
       suspended = &lp;
 
2631
   }
 
2632
 
 
2633
   /* split queues */
 
2634
   where = lWhere("%T(!(%I m= %u) && !(%I m= %u) && !(%I m= %u) && !(%I m= %u))", 
 
2635
      lGetListDescr(*queue_list), 
 
2636
         QU_state, QI_SUSPENDED,
 
2637
         QU_state, QI_CAL_SUSPENDED,
 
2638
         QU_state, QI_CAL_DISABLED,
 
2639
         QU_state, QI_SUSPENDED_ON_SUBORDINATE);
 
2640
 
 
2641
   ret = lSplit(queue_list, &lp, "full queues", where);
 
2642
   lFreeWhere(&where);
 
2643
 
 
2644
   if (lp != NULL) {
 
2645
      lListElem* mes_queue;
 
2646
 
 
2647
      for_each(mes_queue, lp) {
 
2648
         if (!qinstance_state_is_manual_suspended(mes_queue)) {
 
2649
            qinstance_state_set_manual_suspended(mes_queue, true);
 
2650
            schedd_mes_add_global(SCHEDD_INFO_QUEUESUSP_, lGetString(mes_queue, QU_full_name));
 
2651
         }
 
2652
      }   
 
2653
 
 
2654
      schedd_log_list(MSG_SCHEDD_LOGLIST_QUEUESSUSPENDEDANDDROPPED , lp, QU_full_name);
 
2655
   }
 
2656
 
 
2657
   if (suspended != NULL) {
 
2658
      if (*suspended == NULL) {
 
2659
         *suspended = lp;
 
2660
         lp = NULL;
 
2661
      }
 
2662
      else {
 
2663
         lAddList(*suspended, &lp);
 
2664
         lp = NULL;
 
2665
      }
 
2666
   }
 
2667
   else {
 
2668
      lFreeList(suspended);
 
2669
   }
 
2670
      
 
2671
   DRETURN(ret);
 
2672
}
 
2673
 
 
2674
/* ----------------------------------------
 
2675
 
 
2676
   sge_split_cal_disabled()
 
2677
 
 
2678
   splits the incoming queue list (1st arg) into non disabled queues and
 
2679
   cal_disabled queues (2nd arg) 
 
2680
 
 
2681
   lList **queue_list,       QU_Type 
 
2682
   lList **disabled          QU_Type 
 
2683
 
 
2684
   returns:
 
2685
      0 successful
 
2686
     -1 errors in functions called by sge_split_queue_load
 
2687
 
 
2688
*/
 
2689
int 
 
2690
sge_split_cal_disabled(lList **queue_list, lList **disabled) 
 
2691
{
 
2692
   lCondition *where;
 
2693
   int ret;
 
2694
   lList *lp = NULL;
 
2695
   bool do_free_list = false;
 
2696
 
 
2697
   DENTER(TOP_LAYER, "sge_split_disabled");
 
2698
 
 
2699
   if (!queue_list) {
 
2700
      DRETURN(-1);
 
2701
   }
 
2702
 
 
2703
   if (disabled == NULL) {
 
2704
       disabled = &lp;
 
2705
       do_free_list = true;
 
2706
   }
 
2707
 
 
2708
   /* split queues */
 
2709
   where = lWhere("%T(!(%I m= %u))", lGetListDescr(*queue_list), 
 
2710
                  QU_state, QI_CAL_DISABLED);
 
2711
   ret = lSplit(queue_list, disabled, "full queues", where);
 
2712
   lFreeWhere(&where);
 
2713
 
 
2714
   if (*disabled != NULL) {
 
2715
      lListElem* mes_queue;
 
2716
 
 
2717
      for_each(mes_queue, *disabled) {
 
2718
         schedd_mes_add_global(SCHEDD_INFO_QUEUEDISABLED_, lGetString(mes_queue, QU_full_name));
 
2719
      }   
 
2720
 
 
2721
      schedd_log_list(MSG_SCHEDD_LOGLIST_QUEUESDISABLEDANDDROPPED , *disabled, QU_full_name);
 
2722
 
 
2723
      if (do_free_list) {
 
2724
         lFreeList(disabled);
 
2725
      }
 
2726
   }
 
2727
   
 
2728
   DRETURN(ret);
 
2729
}
 
2730
 
 
2731
/* ----------------------------------------
 
2732
 
 
2733
   sge_split_disabled()
 
2734
 
 
2735
   splits the incoming queue list (1st arg) into non disabled queues and
 
2736
   disabled queues (2nd arg) 
 
2737
 
 
2738
   lList **queue_list,       QU_Type 
 
2739
   lList **disabled          QU_Type 
 
2740
 
 
2741
   returns:
 
2742
      0 successful
 
2743
     -1 errors in functions called by sge_split_queue_load
 
2744
 
 
2745
*/
 
2746
int 
 
2747
sge_split_disabled(lList **queue_list, lList **disabled) 
 
2748
{
 
2749
   lCondition *where;
 
2750
   int ret;
 
2751
   lList *lp = NULL;
 
2752
   bool do_free_list = false;
 
2753
 
 
2754
   DENTER(TOP_LAYER, "sge_split_disabled");
 
2755
 
 
2756
   if (!queue_list) {
 
2757
      DRETURN(-1);
 
2758
   }
 
2759
 
 
2760
   if (disabled == NULL) {
 
2761
       disabled = &lp;
 
2762
       do_free_list = true;
 
2763
   }
 
2764
 
 
2765
   /* split queues */
 
2766
   where = lWhere("%T(!(%I m= %u) && !(%I m= %u))", lGetListDescr(*queue_list), 
 
2767
                  QU_state, QI_DISABLED, QU_state, QI_CAL_DISABLED);
 
2768
   ret = lSplit(queue_list, disabled, "full queues", where);
 
2769
   lFreeWhere(&where);
 
2770
 
 
2771
   if (*disabled != NULL) {
 
2772
      lListElem* mes_queue;
 
2773
 
 
2774
      for_each(mes_queue, *disabled) {
 
2775
         schedd_mes_add_global(SCHEDD_INFO_QUEUEDISABLED_, lGetString(mes_queue, QU_full_name));
 
2776
      }   
 
2777
 
 
2778
      schedd_log_list(MSG_SCHEDD_LOGLIST_QUEUESDISABLEDANDDROPPED , *disabled, QU_full_name);
 
2779
 
 
2780
      if (do_free_list) {
 
2781
         lFreeList(disabled);
 
2782
      }
 
2783
   }
 
2784
   
 
2785
   DRETURN(ret);
 
2786
}
 
2787
 
 
2788
/****** sge_select_queue/pe_cq_rejected() **************************************
 
2789
*  NAME
 
2790
*     pe_cq_rejected() -- Check, if -pe pe_name rejects cluster queue
 
2791
*
 
2792
*  SYNOPSIS
 
2793
*     static bool pe_cq_rejected(const char *pe_name, const lListElem *cq)
 
2794
*
 
2795
*  FUNCTION
 
2796
*     Match a jobs -pe 'pe_name' with pe_list cluster queue configuration.
 
2797
*     True is returned if the parallel environment has no access.
 
2798
*
 
2799
*  INPUTS
 
2800
*     const char *project - the pe request of a job (no wildcard)
 
2801
*     const lListElem *cq - cluster queue (CQ_Type)
 
2802
*
 
2803
*  RESULT
 
2804
*     static bool - True, if rejected
 
2805
*
 
2806
*  NOTES
 
2807
*     MT-NOTE: pe_cq_rejected() is MT safe
 
2808
*******************************************************************************/
 
2809
static bool pe_cq_rejected(const char *pe_name, const lListElem *cq)
 
2810
{
 
2811
   const lListElem *alist;
 
2812
   bool rejected;
 
2813
 
 
2814
   DENTER(TOP_LAYER, "pe_cq_rejected");
 
2815
 
 
2816
   if (!pe_name) {
 
2817
      DRETURN(false);
 
2818
   }
 
2819
 
 
2820
   rejected = true;
 
2821
   for_each (alist, lGetList(cq, CQ_pe_list)) {
 
2822
      if (lGetSubStr(alist, ST_name, pe_name, ASTRLIST_value)) {
 
2823
         rejected = false;
 
2824
         break;
 
2825
      }
 
2826
   }
 
2827
 
 
2828
   DRETURN(rejected);
 
2829
}
 
2830
 
 
2831
/****** sge_select_queue/project_cq_rejected() *********************************
 
2832
*  NAME
 
2833
*     project_cq_rejected() -- Check, if -P project rejects cluster queue
 
2834
*
 
2835
*  SYNOPSIS
 
2836
*     static bool project_cq_rejected(const char *project, const lListElem *cq)
 
2837
*
 
2838
*  FUNCTION
 
2839
*     Match a jobs -P 'project' with project/xproject cluster queue configuration.
 
2840
*     True is returned if the project has no access.
 
2841
*
 
2842
*  INPUTS
 
2843
*     const char *project - the project of a job or NULL
 
2844
*     const lListElem *cq - cluster queue (CQ_Type)
 
2845
*
 
2846
*  RESULT
 
2847
*     static bool - True, if rejected
 
2848
*
 
2849
*  NOTES
 
2850
*     MT-NOTE: project_cq_rejected() is MT safe
 
2851
*******************************************************************************/
 
2852
static bool project_cq_rejected(const char *project, const lListElem *cq)
 
2853
{
 
2854
   const lList *projects;
 
2855
   const lListElem *alist;
 
2856
   bool rejected;
 
2857
 
 
2858
   DENTER(TOP_LAYER, "project_cq_rejected");
 
2859
 
 
2860
   if (!project) {
 
2861
      /* without project: rejected, if each "project" profile
 
2862
         does contain project references */
 
2863
      for_each (alist, lGetList(cq, CQ_projects)) {
 
2864
         if (!lGetList(alist, APRJLIST_value)) {
 
2865
            DRETURN(false);
 
2866
         }
 
2867
      }
 
2868
 
 
2869
      DRETURN(true);
 
2870
   }
 
2871
 
 
2872
   /* with project: rejected, if project is excluded by each "xproject" profile */
 
2873
   rejected = true;
 
2874
   for_each (alist, lGetList(cq, CQ_xprojects)) {
 
2875
      projects = lGetList(alist, APRJLIST_value);
 
2876
      if (!projects || !prj_list_locate(projects, project)) {
 
2877
         rejected = false;
 
2878
         break;
 
2879
      }
 
2880
   }
 
2881
   if (rejected) {
 
2882
      DRETURN(true);
 
2883
   }
 
2884
 
 
2885
   /* with project: rejected, if project is not included with each "project" profile */
 
2886
   rejected = true;
 
2887
   for_each (alist, lGetList(cq, CQ_projects)) {
 
2888
      projects = lGetList(alist, APRJLIST_value);
 
2889
      if (!projects || prj_list_locate(projects, project)) {
 
2890
         rejected = false;
 
2891
         break;
 
2892
      }
 
2893
   }
 
2894
   if (rejected) {
 
2895
      DRETURN(true);
 
2896
   }
 
2897
 
 
2898
   DRETURN(false);
 
2899
}
 
2900
 
 
2901
/****** sge_select_queue/interactive_cq_rejected() *****************************
 
2902
*  NAME
 
2903
*     interactive_cq_rejected() --  Check, if -now yes rejects cluster queue
 
2904
*
 
2905
*  SYNOPSIS
 
2906
*     static bool interactive_cq_rejected(const lListElem *cq)
 
2907
*
 
2908
*  FUNCTION
 
2909
*     Returns true if -now yes jobs can not be run in cluster queue
 
2910
*
 
2911
*  INPUTS
 
2912
*     const lListElem *cq - cluster queue (CQ_Type)
 
2913
*
 
2914
*  RESULT
 
2915
*     static bool - True, if rejected
 
2916
*
 
2917
*  NOTES
 
2918
*     MT-NOTE: interactive_cq_rejected() is MT safe
 
2919
*******************************************************************************/
 
2920
static bool interactive_cq_rejected(const lListElem *cq)
 
2921
{
 
2922
   const lListElem *alist;
 
2923
   bool rejected;
 
2924
 
 
2925
   DENTER(TOP_LAYER, "interactive_cq_rejected");
 
2926
 
 
2927
   rejected = true;
 
2928
   for_each (alist, lGetList(cq, CQ_qtype)) {
 
2929
      if ((lGetUlong(alist, AQTLIST_value) & IQ)) {
 
2930
         rejected = false;
 
2931
         break;
 
2932
      }
 
2933
   }
 
2934
 
 
2935
   DRETURN(rejected);
 
2936
}
 
2937
 
 
2938
/****** sge_select_queue/access_cq_rejected() **********************************
 
2939
*  NAME
 
2940
*     access_cq_rejected() -- Check, if cluster queue rejects user/project 
 
2941
*
 
2942
*  SYNOPSIS
 
2943
*     static bool access_cq_rejected(const char *user, const char *group, const 
 
2944
*     lList *acl_list, const lListElem *cq) 
 
2945
*
 
2946
*  FUNCTION
 
2947
*     ??? 
 
2948
*
 
2949
*  INPUTS
 
2950
*     const char *user      - Username 
 
2951
*     const char *group     - Groupname
 
2952
*     const lList *acl_list - List of access list definitions
 
2953
*     const lListElem *cq   - Cluster queue
 
2954
*
 
2955
*  RESULT
 
2956
*     static bool - True, if rejected
 
2957
*
 
2958
*  NOTES
 
2959
*     MT-NOTE: access_cq_rejected() is MT safe 
 
2960
*******************************************************************************/
 
2961
static bool access_cq_rejected(const char *user, const char *group,  
 
2962
      const lList *acl_list, const lListElem *cq)
 
2963
{
 
2964
   const lListElem *alist;
 
2965
   bool rejected;
 
2966
 
 
2967
   DENTER(TOP_LAYER, "access_cq_rejected");
 
2968
 
 
2969
   /* rejected, if user/group is excluded by each "xacl" profile */
 
2970
   rejected = true;
 
2971
   for_each (alist, lGetList(cq, CQ_xacl)) {
 
2972
      if (!sge_contained_in_access_list_(user, group, lGetList(alist, AUSRLIST_value), acl_list)) {
 
2973
         rejected = false;
 
2974
         break;
 
2975
      }
 
2976
   }
 
2977
   if (rejected) {
 
2978
      DRETURN(true);
 
2979
   }
 
2980
 
 
2981
   /* rejected, if user/group is not included in any "acl" profile */
 
2982
   rejected = true;
 
2983
   for_each (alist, lGetList(cq, CQ_acl)) {
 
2984
      const lList *t = lGetList(alist, AUSRLIST_value);
 
2985
      if (!t || sge_contained_in_access_list_(user, group, t, acl_list)) {
 
2986
         rejected = false;
 
2987
         break;
 
2988
      }
 
2989
   }
 
2990
 
 
2991
   DRETURN(rejected);
 
2992
}
 
2993
 
 
2994
/****** sge_select_queue/cqueue_match_static() *********************************
 
2995
*  NAME
 
2996
*     cqueue_match_static() -- Does cluster queue match the job?
 
2997
*
 
2998
*  SYNOPSIS
 
2999
*     static dispatch_t cqueue_match_static(const char *cqname,
 
3000
*     sge_assignment_t *a)
 
3001
*
 
3002
*  FUNCTION
 
3003
*     The function tries to find reasons (-q, -l and -P) why the
 
3004
*     entire cluster is not suited for the job.
 
3005
*
 
3006
*  INPUTS
 
3007
*     const char *cqname  - Cluster queue name
 
3008
*     sge_assignment_t *a - ???
 
3009
*
 
3010
*  RESULT
 
3011
*     static dispatch_t - Returns DISPATCH_OK  or DISPATCH_NEVER_CAT
 
3012
*
 
3013
*  NOTES
 
3014
*     MT-NOTE: cqueue_match_static() is MT safe
 
3015
*******************************************************************************/
 
3016
dispatch_t cqueue_match_static(const char *cqname, sge_assignment_t *a)
 
3017
{
 
3018
   const lList *hard_resource_list;
 
3019
   const lListElem *cq;
 
3020
   const char *project, *pe_name;
 
3021
   u_long32 ar_id;
 
3022
 
 
3023
   DENTER(TOP_LAYER, "cqueue_match_static");
 
3024
 
 
3025
   /* detect if entire cluster queue ruled out due to -q */
 
3026
   if (qref_list_cq_rejected(lGetList(a->job, JB_hard_queue_list), cqname, NULL, NULL) &&
 
3027
       (!a->pe_name || qref_list_cq_rejected(lGetList(a->job, JB_master_hard_queue_list), cqname, NULL, NULL))) {
 
3028
      DPRINTF(("Cluster Queue \"%s\" is not contained in the hard queue list (-q) that "
 
3029
            "was requested by job %d\n", cqname, (int)a->job_id));
 
3030
      schedd_mes_add(a->job_id, SCHEDD_INFO_NOTINHARDQUEUELST_S, cqname);
 
3031
      DRETURN(DISPATCH_NEVER_CAT);
 
3032
   }
 
3033
   
 
3034
   /* check if cqueue was reserved for AR job */
 
3035
   ar_id = lGetUlong(a->job, JB_ar);
 
3036
   if (ar_id != 0) {
 
3037
      lListElem *ar_ep = lGetElemUlong(a->ar_list, AR_id, ar_id);
 
3038
 
 
3039
      if (ar_ep != NULL) {
 
3040
         lListElem *gep = NULL;
 
3041
 
 
3042
         for_each(gep, lGetList(ar_ep, AR_granted_slots)) {
 
3043
            char *ar_cqueue = cqueue_get_name_from_qinstance(lGetString(gep, JG_qname));
 
3044
 
 
3045
            if (strcmp(cqname, ar_cqueue) == 0) {
 
3046
               /* found queue */
 
3047
               FREE(ar_cqueue);
 
3048
               break;
 
3049
            }
 
3050
            FREE(ar_cqueue);
 
3051
         }
 
3052
 
 
3053
         if (gep == NULL) {
 
3054
 
 
3055
            DPRINTF(("Cluster Queue \"%s\" was not reserved by advance reservation %d\n", cqname, ar_id));
 
3056
            schedd_mes_add(a->job_id, SCHEDD_INFO_QINOTARRESERVED_SI, cqname, ar_id);
 
3057
            DRETURN(DISPATCH_NEVER_CAT);
 
3058
         }
 
3059
      } else {
 
3060
         /* should never happen */
 
3061
         DRETURN(DISPATCH_NEVER_CAT);
 
3062
      }
 
3063
   }
 
3064
 
 
3065
   cq = lGetElemStr(*(object_type_get_master_list(SGE_TYPE_CQUEUE)), CQ_name, cqname);
 
3066
 
 
3067
   /* detect if entire cluster queue ruled out due to -l */
 
3068
   if ((hard_resource_list = lGetList(a->job, JB_hard_resource_list))) {
 
3069
      dstring unsatisfied = DSTRING_INIT;
 
3070
      if (request_cq_rejected(hard_resource_list, cq, a->centry_list, 
 
3071
                     (!a->pe_name || a->slots == 1)?true:false, &unsatisfied)) {
 
3072
         DPRINTF(("Cluster Queue \"%s\" can not fulfill resource request (-l %s) that "
 
3073
               "was requested by job %d\n", cqname, sge_dstring_get_string(&unsatisfied), (int)a->job_id));
 
3074
         schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNINQUEUE_SSS, sge_dstring_get_string(&unsatisfied),
 
3075
               cqname, "of cluster queue");
 
3076
         sge_dstring_free(&unsatisfied);
 
3077
         DRETURN(DISPATCH_NEVER_CAT);
 
3078
      }
 
3079
   }
 
3080
 
 
3081
   /* detect if entire cluster queue ruled out due to -P */
 
3082
   project = a->project;
 
3083
   if (project_cq_rejected(project, cq)) {
 
3084
      DPRINTF(("Cluster queue \"%s\" does not work for -P %s job %d\n",
 
3085
         cqname, project?project:"<no project>", (int)a->job_id));
 
3086
      schedd_mes_add(a->job_id, SCHEDD_INFO_HASNOPRJ_S, "cluster queue", cqname);
 
3087
      DRETURN(DISPATCH_NEVER_CAT);
 
3088
   }
 
3089
 
 
3090
   /* detect if entire cluster queue ruled out due to user_list/xuser_lists */
 
3091
   if (access_cq_rejected(a->user, a->group, a->acl_list, cq)) {
 
3092
      DPRINTF(("Job %d has no permission for cluster queue %s\n", (int)a->job_id, cqname));
 
3093
      schedd_mes_add(a->job_id, SCHEDD_INFO_HASNOPERMISSION_SS, "cluster queue", cqname);
 
3094
      DRETURN(DISPATCH_NEVER_CAT);
 
3095
   }
 
3096
 
 
3097
   /* detect if entire cluster queue ruled out due to -pe */
 
3098
   if (a->pe && (pe_name=a->pe_name) && pe_cq_rejected(pe_name, cq)) {
 
3099
      DPRINTF(("Cluster queue "SFQ" does not reference PE "SFQ"\n", cqname, pe_name));
 
3100
      schedd_mes_add(a->job_id, SCHEDD_INFO_NOTINQUEUELSTOFPE_SS, cqname, pe_name);
 
3101
      DRETURN(DISPATCH_NEVER_CAT);
 
3102
   }
 
3103
 
 
3104
   /* detect if entire cluster queue ruled out due to -I y aka -now yes */
 
3105
   if (JOB_TYPE_IS_IMMEDIATE(lGetUlong(a->job, JB_type)) && interactive_cq_rejected(cq)) {
 
3106
      DPRINTF(("Queue \"%s\" is not an interactive queue as requested by job %d\n",
 
3107
               cqname, (int)a->job_id));
 
3108
      schedd_mes_add(a->job_id, SCHEDD_INFO_QUEUENOTINTERACTIVE_S, cqname);
 
3109
      DRETURN(DISPATCH_NEVER_CAT);
 
3110
   }
 
3111
 
 
3112
   DRETURN(DISPATCH_OK);
 
3113
}
 
3114
 
 
3115
 
 
3116
/****** sge_select_queue/sequential_tag_queues_suitable4job() **************
 
3117
*  NAME
 
3118
*     sequential_tag_queues_suitable4job() -- ??? 
 
3119
*
 
3120
*  SYNOPSIS
 
3121
*
 
3122
*  FUNCTION
 
3123
*     The start time of a queue is always returned using the QU_available_at 
 
3124
*     field.
 
3125
*
 
3126
*     The overall behaviour of this function is somewhat dependent on the 
 
3127
*     value that gets passed to assignment->start and whether soft requests 
 
3128
*     were specified with the job: 
 
3129
*
 
3130
*     (1) In case of now assignemnts (DISPATCH_TIME_NOW) only the first queue 
 
3131
*         suitable for jobs without soft requests is tagged. When soft requests 
 
3132
*         are specified all queues must be verified and tagged in order to find 
 
3133
*         the queue that fits best. 
 
3134
*
 
3135
*     (2) In case of reservation assignments (DISPATCH_TIME_QUEUE_END) the earliest
 
3136
*         time is searched when the resources of global/host/queue are sufficient
 
3137
*         for the job. The time-wise iteration is then done for each single resources 
 
3138
*         instance. 
 
3139
*
 
3140
*         Actually there are cases when iterating through all queues were not 
 
3141
*         needed: (a) if there was a global limitation search could stop once
 
3142
*         a queue is found that causes no further delay (b) if job has
 
3143
*         a soft request search could stop once a queue is found with minimum (=0)
 
3144
*         soft violations.
 
3145
*
 
3146
*  INPUTS
 
3147
*     sge_assignment_t *assignment - job info structure
 
3148
*
 
3149
*  RESULT
 
3150
*     dispatch_t - 0 ok got an assignment 
 
3151
*                    start time(s) and slots are tagged
 
3152
*                  1 no assignment at the specified time
 
3153
*                 -1 assignment will never be possible for all jobs of that category
 
3154
*                 -2 assignment will never be possible for that particular job
 
3155
*
 
3156
*  NOTES
 
3157
*     MT-NOTE: sequential_tag_queues_suitable4job() is not MT safe 
 
3158
*******************************************************************************/
 
3159
static dispatch_t
 
3160
sequential_tag_queues_suitable4job(sge_assignment_t *a)
 
3161
{
 
3162
   lList *skip_host_list = NULL;
 
3163
   lList *skip_queue_list = NULL;
 
3164
 
 
3165
   lList *unclear_cqueue_list = NULL;
 
3166
   lList *unclear_host_list = NULL;
 
3167
   dstring rule_name = DSTRING_INIT;
 
3168
   dstring rue_string = DSTRING_INIT;
 
3169
   dstring limit_name = DSTRING_INIT;
 
3170
   u_long32 ar_id = lGetUlong(a->job, JB_ar);
 
3171
   lListElem *ar_ep = lGetElemUlong(a->ar_list, AR_id, ar_id);
 
3172
 
 
3173
   category_use_t use_category;
 
3174
   bool got_solution = false;
 
3175
   u_long32 tt_best = U_LONG32_MAX;
 
3176
   u_long32 violations_best = U_LONG32_MAX;
 
3177
 
 
3178
   dispatch_t result;
 
3179
   u_long32 tt_global = a->start;
 
3180
   dispatch_t best_queue_result = DISPATCH_NEVER_CAT;
 
3181
   int global_violations = 0;
 
3182
   int queue_violations = 0;
 
3183
   lListElem *qep;
 
3184
 
 
3185
   DENTER(TOP_LAYER, "sequential_tag_queues_suitable4job");
 
3186
 
 
3187
   /* assemble job category information */
 
3188
   fill_category_use_t(a, &use_category, "NONE");   
 
3189
   
 
3190
   /* restore job messages from previous dispatch runs of jobs of the same category */
 
3191
   if (use_category.use_category) {
 
3192
      schedd_mes_set_tmp_list(use_category.cache, CCT_job_messages, a->job_id);
 
3193
      skip_host_list = lGetList(use_category.cache, CCT_ignore_hosts);
 
3194
      skip_queue_list = lGetList(use_category.cache, CCT_ignore_queues);
 
3195
   }
 
3196
 
 
3197
   if (ar_ep != NULL) {
 
3198
      result = match_static_advance_reservation(a);
 
3199
      if (result != DISPATCH_OK) {
 
3200
         DRETURN(result);
 
3201
      }
 
3202
   } else {
 
3203
      if (a->pi)
 
3204
         a->pi->seq_global++;
 
3205
      result = sequential_global_time(&tt_global, a, &global_violations); 
 
3206
      if (result != DISPATCH_OK && result != DISPATCH_MISSING_ATTR) {
 
3207
         DRETURN(result);
 
3208
      }
 
3209
   }
 
3210
   
 
3211
   for_each(qep, a->queue_list) {   
 
3212
      u_long32 tt_host = a->start;
 
3213
      u_long32 tt_queue = a->start;   
 
3214
      const char *eh_name;
 
3215
      const char *qname, *cqname;
 
3216
      u_long32 tt_rqs = 0;   
 
3217
      bool is_global;
 
3218
 
 
3219
      lListElem *hep;
 
3220
 
 
3221
      qname = lGetString(qep, QU_full_name);
 
3222
      cqname = lGetString(qep, QU_qname);
 
3223
      eh_name = lGetHost(qep, QU_qhostname);
 
3224
 
 
3225
      /* try to foreclose the cluster queue */
 
3226
      if (lGetElemStr(a->skip_cqueue_list, CTI_name, cqname)) {
 
3227
         DPRINTF(("skip cluster queue %s\n", cqname));
 
3228
         continue;
 
3229
      }
 
3230
      if (lGetElemStr(a->skip_host_list, CTI_name, eh_name)) {
 
3231
         DPRINTF(("rqs skip host %s\n", eh_name));
 
3232
         continue;
 
3233
      }
 
3234
      if (skip_host_list && lGetElemStr(skip_host_list, CTI_name, eh_name)){
 
3235
         DPRINTF(("job category skip host %s\n", eh_name));
 
3236
         continue;
 
3237
      }
 
3238
 
 
3239
      if (skip_queue_list && lGetElemStr(skip_queue_list, CTI_name, qname)){
 
3240
         DPRINTF(("job category skip queue %s\n", qname));
 
3241
         continue;
 
3242
      }
 
3243
 
 
3244
      if (!ar_ep) {
 
3245
         /* resource quota matching */
 
3246
         if ((result = rqs_by_slots(a, cqname, eh_name, &tt_rqs, &is_global, 
 
3247
                  &rue_string, &limit_name, &rule_name, got_solution?tt_best:U_LONG32_MAX)) != DISPATCH_OK) {
 
3248
            best_queue_result = find_best_result(result, best_queue_result);
 
3249
            if (is_global == false) {
 
3250
               DPRINTF(("no match due to GLOBAL RQS\n", eh_name));          
 
3251
               continue;
 
3252
            }
 
3253
            break; /* hit a global limit */
 
3254
         }
 
3255
         if (got_solution && is_not_better(a, violations_best, tt_best, 0, tt_rqs)) {
 
3256
            DPRINTF(("CUT TREE: Due to RQS for \"%s\"\n", qname));
 
3257
            if (is_global == false)
 
3258
               continue;
 
3259
            break;
 
3260
         }
 
3261
      }
 
3262
 
 
3263
 
 
3264
      /* static cqueue matching */
 
3265
      if (!lGetElemStr(unclear_cqueue_list, CTI_name, cqname)) {
 
3266
         
 
3267
         if (a->pi)
 
3268
            a->pi->seq_cqstat++;
 
3269
         if (cqueue_match_static(cqname, a) != DISPATCH_OK) {
 
3270
            lAddElemStr(&(a->skip_cqueue_list), CTI_name, cqname, CTI_Type);
 
3271
            best_queue_result = find_best_result(DISPATCH_NEVER_CAT, best_queue_result);
 
3272
            continue;
 
3273
         }
 
3274
         lAddElemStr(&unclear_cqueue_list, CTI_name, cqname, CTI_Type);
 
3275
      }
 
3276
 
 
3277
      /* static host matching */
 
3278
      if (!(hep = lGetElemHost(a->host_list, EH_name, eh_name))) {
 
3279
         ERROR((SGE_EVENT, MSG_SCHEDD_UNKNOWN_HOST_SS, qname, eh_name));
 
3280
         if (skip_queue_list != NULL) {
 
3281
            lAddElemStr(&skip_queue_list, CTI_name, qname, CTI_Type);
 
3282
         }
 
3283
         continue;
 
3284
      }
 
3285
      if (!lGetElemStr(unclear_host_list, CTI_name, eh_name)) {
 
3286
         if (a->pi)
 
3287
            a->pi->seq_hstat++;
 
3288
         if (qref_list_eh_rejected(lGetList(a->job, JB_hard_queue_list), eh_name, a->hgrp_list)) {
 
3289
            schedd_mes_add(a->job_id, SCHEDD_INFO_NOTINHARDQUEUELST_S, eh_name);
 
3290
            DPRINTF(("Host \"%s\" is not contained in the hard queue list (-q) that "
 
3291
                  "was requested by job %d\n", eh_name, (int)a->job_id));
 
3292
            if (skip_host_list)
 
3293
               lAddElemStr(&skip_host_list, CTI_name, eh_name, CTI_Type);
 
3294
            else
 
3295
               lAddElemStr(&(a->skip_host_list), CTI_name, eh_name, CTI_Type);
 
3296
            best_queue_result = find_best_result(DISPATCH_NEVER_CAT, best_queue_result);
 
3297
            continue;
 
3298
         }
 
3299
 
 
3300
         if ((result=sge_host_match_static(a->job, a->ja_task, hep, a->centry_list, a->acl_list))) {
 
3301
            if (result == DISPATCH_NEVER_JOB || !skip_host_list)
 
3302
               lAddElemStr(&(a->skip_host_list), CTI_name, eh_name, CTI_Type);
 
3303
            else
 
3304
               lAddElemStr(&(a->skip_host_list), CTI_name, eh_name, CTI_Type);
 
3305
            best_queue_result = find_best_result(result, best_queue_result);
 
3306
            continue;
 
3307
         }
 
3308
         lAddElemStr(&unclear_host_list, CTI_name, eh_name, CTI_Type);
 
3309
      }
 
3310
 
 
3311
      /* static queue matching */
 
3312
      if (a->pi)
 
3313
         a->pi->seq_qstat++;
 
3314
      if (sge_queue_match_static(qep, a->job, NULL, a->ckpt, a->centry_list,
 
3315
                                 a->acl_list, a->hgrp_list, a->ar_list) != DISPATCH_OK) {
 
3316
         if (skip_queue_list)
 
3317
            lAddElemStr(&skip_queue_list, CTI_name, qname, CTI_Type);
 
3318
         best_queue_result = find_best_result(DISPATCH_NEVER_CAT, best_queue_result);
 
3319
         continue;
 
3320
      }
 
3321
 
 
3322
      /* ar matching */
 
3323
      if (ar_ep != NULL) {
 
3324
         lListElem *ar_queue;
 
3325
         lListElem *rep;
 
3326
         dstring reason = DSTRING_INIT;
 
3327
 
 
3328
         ar_queue = lGetSubStr(ar_ep, QU_full_name, qname, AR_reserved_queues);
 
3329
 
 
3330
         /* 
 
3331
          * We are only interested in the static complexes on queue/host level. 
 
3332
          * These are tagged in this function. The result doesn't matter 
 
3333
          */
 
3334
         for_each(rep, lGetList(a->job, JB_hard_resource_list)) {
 
3335
            const char *attrname = lGetString(rep, CE_name);
 
3336
            lListElem *cplx_el = lGetElemStr(a->centry_list, CE_name, attrname);
 
3337
 
 
3338
            if (lGetBool(cplx_el, CE_consumable)) {
 
3339
               continue;
 
3340
            }
 
3341
            sge_dstring_clear(&reason);
 
3342
            cplx_el = get_attribute_by_name(a->gep, hep, qep, attrname, a->centry_list, a->start, a->duration);
 
3343
            if (cplx_el == NULL) { 
 
3344
               result = DISPATCH_MISSING_ATTR;
 
3345
               sge_dstring_sprintf(&reason, MSG_ATTRIB_MISSINGATTRIBUTEXINCOMPLEXES_S, attrname);
 
3346
               break;
 
3347
            }
 
3348
 
 
3349
            result = match_static_resource(1, rep, cplx_el, &reason, false, false, false);
 
3350
            lFreeElem(&cplx_el);
 
3351
            if (result != DISPATCH_OK) {
 
3352
               break;
 
3353
            }
 
3354
            lSetUlong(rep, CE_tagged, HOST_TAG); 
 
3355
         }
 
3356
         if (result != DISPATCH_OK) {
 
3357
            char buff[1024 + 1];
 
3358
            centry_list_append_to_string(lGetList(a->job, JB_hard_resource_list), buff, sizeof(buff) - 1);
 
3359
            if (*buff && (buff[strlen(buff) - 1] == '\n')) {
 
3360
               buff[strlen(buff) - 1] = 0;
 
3361
            }
 
3362
            schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNATHOST_SSS, buff,
 
3363
                           lGetHost(hep, EH_name), sge_dstring_get_string(&reason));
 
3364
         } else {
 
3365
            result = sequential_queue_time(&tt_queue, a, &queue_violations, ar_queue);
 
3366
            if (result != DISPATCH_OK) {
 
3367
               DPRINTF(("ar queue %s returned %d\n", qname, result));         
 
3368
               if (skip_queue_list) {
 
3369
                  lAddElemStr(&skip_queue_list, CTI_name, lGetString(ar_queue, QU_full_name), CTI_Type);
 
3370
               }
 
3371
               best_queue_result = find_best_result(result, best_queue_result); 
 
3372
               continue;
 
3373
            }
 
3374
            tt_global = tt_host = tt_queue;
 
3375
         }
 
3376
         sge_dstring_free(&reason);
 
3377
      } else {
 
3378
         queue_violations = global_violations;
 
3379
 
 
3380
         /* dynamic host matching */
 
3381
         if (a->pi)
 
3382
            a->pi->seq_hdyn++;
 
3383
         result = sequential_host_time(&tt_host, a, &queue_violations, hep);
 
3384
         if (result != DISPATCH_OK && result != DISPATCH_MISSING_ATTR) {
 
3385
            if (skip_host_list)
 
3386
               lAddElemStr(&skip_host_list, CTI_name, eh_name, CTI_Type);
 
3387
            else
 
3388
               lAddElemStr(&(a->skip_host_list), CTI_name, eh_name, CTI_Type);
 
3389
            DPRINTF(("host %s returned %d\n", eh_name, result));         
 
3390
            best_queue_result = find_best_result(result, best_queue_result); 
 
3391
            continue;
 
3392
         }
 
3393
         if (got_solution && is_not_better(a, violations_best, tt_best, queue_violations, tt_host)) {
 
3394
            lAddElemStr(&(a->skip_host_list), CTI_name, eh_name, CTI_Type);
 
3395
            DPRINTF(("CUT TREE: Due to HOST for \"%s\"\n", qname));
 
3396
            continue;
 
3397
         }
 
3398
 
 
3399
         /* dynamic queue matching */
 
3400
         if (a->pi)
 
3401
            a->pi->seq_qdyn++;
 
3402
         result = sequential_queue_time(&tt_queue, a, &queue_violations, qep);
 
3403
         if (result != DISPATCH_OK) {
 
3404
            DPRINTF(("queue %s returned %d\n", qname, result));         
 
3405
            if (skip_queue_list) { 
 
3406
               lAddElemStr(&skip_queue_list, CTI_name, qname, CTI_Type);
 
3407
            }
 
3408
            best_queue_result = find_best_result(result, best_queue_result); 
 
3409
            continue;
 
3410
         }
 
3411
         if (got_solution && is_not_better(a, violations_best, tt_best, queue_violations, tt_queue)) {
 
3412
            DPRINTF(("CUT TREE: Due to QUEUE for \"%s\"\n", qname));
 
3413
            continue;
 
3414
         }
 
3415
      }
 
3416
 
 
3417
      if (result == DISPATCH_OK) {
 
3418
         u_long32 this_tt = 0, this_violations = 0;
 
3419
         lSetUlong(qep, QU_tag, 1); /* tag number of slots per queue and time when it will be available */
 
3420
        
 
3421
         
 
3422
         if (a->start == DISPATCH_TIME_QUEUE_END) {
 
3423
 
 
3424
 
 
3425
            DPRINTF(("    global "sge_u32" host "sge_u32" queue "sge_u32" rqs "sge_u32"\n", 
 
3426
                  tt_global, tt_host, tt_queue, tt_rqs));
 
3427
            lSetUlong(qep, QU_available_at, this_tt = MAX(tt_queue, MAX(tt_host, MAX(tt_rqs, tt_global))));
 
3428
         }
 
3429
         if (a->is_soft) {
 
3430
            this_violations = lGetUlong(qep, QU_soft_violation);
 
3431
         }
 
3432
         DPRINTF(("    set Q: %s number=1 when="sge_u32" violations="sge_u32"\n", qname, this_tt, this_violations));
 
3433
         best_queue_result = DISPATCH_OK;
 
3434
 
 
3435
         if (!a->is_reservation) {
 
3436
            if (!a->is_soft || this_violations == 0)
 
3437
               break;
 
3438
         } else {
 
3439
            /* further search is pointless, if reservation depends from a global consumble */
 
3440
            /* earlier start time has higher preference than lower soft violations */
 
3441
            if (ar_ep == NULL && tt_global >= MAX(MAX(tt_queue, tt_host), tt_rqs) && (!a->is_soft || this_violations == 0))
 
3442
               break;
 
3443
         }
 
3444
         got_solution = true;
 
3445
         violations_best = this_violations;
 
3446
         tt_best = this_tt;
 
3447
      } else {
 
3448
         DPRINTF(("queue %s reported %d\n", qname, result));
 
3449
         if (skip_queue_list) {
 
3450
            lAddElemStr(&skip_queue_list, CTI_name, qname, CTI_Type);
 
3451
         }
 
3452
         best_queue_result = find_best_result(result, best_queue_result); 
 
3453
      }
 
3454
   }
 
3455
 
 
3456
   lFreeList(&unclear_cqueue_list);
 
3457
   lFreeList(&unclear_host_list);
 
3458
 
 
3459
   /* cache so far generated messages with the job category */
 
3460
   if (use_category.use_category) {  
 
3461
      lList *temp = schedd_mes_get_tmp_list();
 
3462
      if (temp){    
 
3463
         lSetList(use_category.cache, CCT_job_messages, lCopyList(NULL, temp));
 
3464
      }
 
3465
   }
 
3466
   
 
3467
   sge_dstring_free(&rue_string);
 
3468
   sge_dstring_free(&limit_name);
 
3469
   sge_dstring_free(&rule_name);
 
3470
 
 
3471
   DRETURN(best_queue_result);
 
3472
}
 
3473
 
 
3474
 
 
3475
 
 
3476
/****** sge_select_queue/add_pe_slots_to_category() ****************************
 
3477
*  NAME
 
3478
*     add_pe_slots_to_category() -- defines an array of valid slot values
 
3479
*
 
3480
*  SYNOPSIS
 
3481
*     static bool add_pe_slots_to_category(category_use_t *use_category, 
 
3482
*     u_long32 *max_slotsp, lListElem *pe, int min_slots, int max_slots, lList 
 
3483
*     *pe_range) 
 
3484
*
 
3485
*  FUNCTION
 
3486
*     In case of pe ranges does this function alocate memory and filles it wil
 
3487
*     valid pe slot values. If a category is set, it stores them the category
 
3488
*     for further jobs. 
 
3489
*
 
3490
*  INPUTS
 
3491
*     category_use_t *use_category - category caching structure, must not be NULL
 
3492
*     u_long32 *max_slotsp         - number of different slot settings
 
3493
*     lListElem *pe                - pe, must not be NULL
 
3494
*     int min_slots                - min slot setting (pe range)
 
3495
*     int max_slots                - max slot setting (pe range)
 
3496
*     lList *pe_range              - pe range, must not be NULL
 
3497
*
 
3498
*  RESULT
 
3499
*     static bool - true, if successfull 
 
3500
*
 
3501
*  NOTES
 
3502
*     MT-NOTE: add_pe_slots_to_category() is MT safe 
 
3503
*
 
3504
*******************************************************************************/
 
3505
static bool 
 
3506
add_pe_slots_to_category(category_use_t *use_category, u_long32 *max_slotsp, lListElem *pe, 
 
3507
                         int min_slots, int max_slots, lList *pe_range)
 
3508
{
 
3509
   if (use_category->cache != NULL) {
 
3510
      use_category->posible_pe_slots = lGetRef(use_category->cache, CCT_pe_job_slots); 
 
3511
   }
 
3512
   
 
3513
   /* --- prepare the posible slots for the binary search */
 
3514
   if (use_category->posible_pe_slots == NULL) {
 
3515
      int slots;
 
3516
 
 
3517
      *max_slotsp = 0;
 
3518
      for (slots = min_slots; slots <= max_slots; slots++) {
 
3519
 
 
3520
         /* sort out slot numbers that would conflict with allocation rule */
 
3521
         if (sge_pe_slots_per_host(pe, slots) == 0) {
 
3522
            continue;
 
3523
         }   
 
3524
 
 
3525
         /* only slot numbers from jobs PE range request */
 
3526
         if (range_list_is_id_within(pe_range, slots) == 0) {
 
3527
            continue;
 
3528
         }   
 
3529
 
 
3530
         if (use_category->posible_pe_slots == NULL) {
 
3531
            use_category->posible_pe_slots = malloc((max_slots - min_slots + 1) * sizeof(u_long32));
 
3532
            if (use_category->posible_pe_slots == NULL) {
 
3533
               return false;
 
3534
            }
 
3535
         }
 
3536
         use_category->posible_pe_slots[(*max_slotsp)] = slots;
 
3537
         (*max_slotsp)++;
 
3538
      }
 
3539
      
 
3540
      if (use_category->cache != NULL) {
 
3541
         lSetRef(use_category->cache, CCT_pe_job_slots, use_category->posible_pe_slots);
 
3542
         lSetUlong(use_category->cache, CCT_pe_job_slot_count, *max_slotsp);
 
3543
         use_category->is_pe_slots_rev = true;
 
3544
      }
 
3545
      else {
 
3546
         use_category->is_pe_slots_rev = false; 
 
3547
      }
 
3548
   }
 
3549
   else {
 
3550
      use_category->is_pe_slots_rev = true;
 
3551
      *max_slotsp = lGetUlong(use_category->cache, CCT_pe_job_slot_count);
 
3552
   }
 
3553
   return true;
 
3554
}
 
3555
 
 
3556
/****** sge_select_queue/fill_category_use_t() **************
 
3557
*  NAME
 
3558
*     fill_category_use_t() -- fills the category_use_t structure.
 
3559
*
 
3560
*  SYNOPSIS
 
3561
*     void fill_category_use_t(sge_assignment_t *a, category_use_t 
 
3562
*     *use_category, const char *pe_name) 
 
3563
*
 
3564
*  FUNCTION
 
3565
*     If a cache structure for the given PE does not exist, it
 
3566
*     will generate the neccissary data structures. 
 
3567
*
 
3568
*  INPUTS
 
3569
*     sge_assignment_t *a          - job info structure (in)
 
3570
*     category_use_t *use_category - category info structure (out)
 
3571
*     const char* pe_name          - the current pe name or "NONE"
 
3572
*
 
3573
*  NOTES
 
3574
*     MT-NOTE: fill_category_use_t() is MT safe 
 
3575
*******************************************************************************/
 
3576
static void fill_category_use_t(const sge_assignment_t *a, category_use_t *use_category, const char *pe_name) 
 
3577
{
 
3578
   lListElem *job = a->job;
 
3579
 
 
3580
   DENTER(TOP_LAYER, "fill_category_use_t");
 
3581
 
 
3582
   use_category->category = lGetRef(job, JB_category);
 
3583
   if (use_category->category != NULL) {
 
3584
      use_category->cache = lGetElemStr(lGetList(use_category->category, CT_cache), CCT_pe_name, pe_name);
 
3585
      if (use_category->cache == NULL) {
 
3586
         use_category->cache = lCreateElem(CCT_Type);
 
3587
 
 
3588
         lSetString(use_category->cache, CCT_pe_name, pe_name);
 
3589
         lSetList(use_category->cache, CCT_ignore_queues, lCreateList("", CTI_Type));
 
3590
         lSetList(use_category->cache, CCT_ignore_hosts, lCreateList("", CTI_Type));
 
3591
         lSetList(use_category->cache, CCT_job_messages, lCreateList("", MES_Type));
 
3592
            
 
3593
         if (lGetList(use_category->category, CT_cache) == NULL) {
 
3594
            lSetList(use_category->category, CT_cache, lCreateList("pe_cache", CCT_Type));
 
3595
         }
 
3596
         lAppendElem(lGetList(use_category->category, CT_cache), use_category->cache);
 
3597
      }
 
3598
 
 
3599
      use_category->mod_category = true; 
 
3600
 
 
3601
      use_category->use_category = ((a->start == DISPATCH_TIME_NOW) && 
 
3602
                                  lGetUlong(use_category->category, CT_refcount) > MIN_JOBS_IN_CATEGORY) ? true : false;
 
3603
   }
 
3604
   else {
 
3605
      use_category->cache = NULL;
 
3606
      use_category->mod_category = false;
 
3607
      use_category->use_category = false;
 
3608
   }
 
3609
   use_category->posible_pe_slots = NULL;
 
3610
   use_category->is_pe_slots_rev = false;
 
3611
 
 
3612
   DRETURN_VOID;
 
3613
}
 
3614
 
 
3615
static int get_soft_violations(sge_assignment_t *a, lListElem *hep, lListElem *qep)
 
3616
{
 
3617
   int violations;
 
3618
 
 
3619
   violations = compute_soft_violations(a, NULL, 0, 
 
3620
         lGetList(a->gep, EH_load_list), 
 
3621
         lGetList(a->gep, EH_consumable_config_list), 
 
3622
         lGetList(a->gep, EH_resource_utilization), 
 
3623
         DOMINANT_LAYER_GLOBAL, 0, GLOBAL_TAG);
 
3624
 
 
3625
   violations = compute_soft_violations(a, NULL, violations, 
 
3626
         lGetList(hep, EH_load_list), 
 
3627
         lGetList(hep, EH_consumable_config_list),
 
3628
         lGetList(hep, EH_resource_utilization), 
 
3629
         DOMINANT_LAYER_HOST, 0, HOST_TAG);
 
3630
 
 
3631
   violations = compute_soft_violations(a, qep, violations, 
 
3632
         NULL, 
 
3633
         lGetList(qep, QU_consumable_config_list), 
 
3634
         lGetList(qep, QU_resource_utilization), 
 
3635
         DOMINANT_LAYER_QUEUE, 0, QUEUE_TAG);
 
3636
 
 
3637
   return violations;
 
3638
}
 
3639
 
 
3640
 
 
3641
/****** sge_select_queue/parallel_tag_queues_suitable4job() *********
 
3642
*  NAME
 
3643
*     parallel_tag_queues_suitable4job() -- Tag queues/hosts for 
 
3644
*        a comprehensive/parallel assignment
 
3645
*
 
3646
*  SYNOPSIS
 
3647
*     static int parallel_tag_queues_suitable4job(sge_assignment_t 
 
3648
*                *assignment) 
 
3649
*
 
3650
*  FUNCTION
 
3651
*     We tag the amount of available slots for that job at global, host and 
 
3652
*     queue level under consideration of all constraints of the job. We also 
 
3653
*     mark those queues that are suitable as a master queue as possible master 
 
3654
*     queues and count the number of violations of the job's soft request. 
 
3655
*     The method below is named comprehensive since it does the tagging game
 
3656
*     for the whole parallel job and under consideration of all available 
 
3657
*     resources that could help to suffice the jobs request. This is necessary 
 
3658
*     to prevent consumable resource limited at host/global level multiple 
 
3659
*     times. 
 
3660
*
 
3661
*     While tagging we also set queues QU_host_seq_no based on the sort 
 
3662
*     order of each host. Assumption is the host list passed is sorted 
 
3663
*     according the load forumla. 
 
3664
*
 
3665
*  INPUTS
 
3666
*     sge_assignment_t *assignment - ??? 
 
3667
*     category_use_t use_category - information on how to use the job category
 
3668
*
 
3669
*  RESULT
 
3670
*     static dispatch_t - 0 ok got an assignment
 
3671
*                         1 no assignment at the specified time
 
3672
*                        -1 assignment will never be possible for all jobs of that category
 
3673
*                        -2 assignment will never be possible for that particular job
 
3674
*
 
3675
*  NOTES
 
3676
*     MT-NOTE: parallel_tag_queues_suitable4job() is not MT safe 
 
3677
*******************************************************************************/
 
3678
static dispatch_t
 
3679
parallel_tag_queues_suitable4job(sge_assignment_t *a, category_use_t *use_category, int *available_slots) 
 
3680
{
 
3681
   lListElem *job = a->job;
 
3682
   bool need_master_host = (lGetList(job, JB_master_hard_queue_list) != NULL) ? true : false;
 
3683
 
 
3684
   int accu_host_slots, accu_host_slots_qend;
 
3685
   bool have_master_host, have_master_host_qend, suited_as_master_host, suited_as_master_host_qend = false;
 
3686
   lListElem *hep;
 
3687
   dispatch_t best_result = DISPATCH_NEVER_CAT; 
 
3688
   int gslots = a->slots;
 
3689
   int gslots_qend = 0;
 
3690
   int allocation_rule, minslots;
 
3691
   dstring rule_name = DSTRING_INIT;
 
3692
   dstring rue_name = DSTRING_INIT;
 
3693
   dstring limit_name = DSTRING_INIT;
 
3694
   lListElem *gdil_ep;
 
3695
 
 
3696
   DENTER(TOP_LAYER, "parallel_tag_queues_suitable4job");
 
3697
 
 
3698
   clean_up_parallel_job(a); 
 
3699
 
 
3700
   if (use_category->use_category) {
 
3701
      schedd_mes_set_tmp_list(use_category->cache, CCT_job_messages, a->job_id);
 
3702
   }
 
3703
 
 
3704
   /* remove reasons from last unsuccesful iteration */ 
 
3705
   clean_monitor_alp();
 
3706
 
 
3707
   if (lGetUlong(a->job, JB_ar) == 0) {
 
3708
      if (a->pi)
 
3709
         a->pi->par_global++;
 
3710
      parallel_global_slots(a, &gslots, &gslots_qend); 
 
3711
   }
 
3712
 
 
3713
   if (gslots < a->slots) {
 
3714
      best_result = (gslots_qend < a->slots) ? DISPATCH_NEVER_CAT : DISPATCH_NOT_AT_TIME;
 
3715
      *available_slots = gslots_qend;
 
3716
 
 
3717
      if (best_result == DISPATCH_NOT_AT_TIME) {
 
3718
         DPRINTF(("GLOBAL will <category_later> get us %d slots (%d)\n", 
 
3719
            gslots, gslots_qend));
 
3720
      } else {
 
3721
         DPRINTF(("GLOBAL will <category_never> get us %d slots (%d)\n", 
 
3722
            gslots, gslots_qend));
 
3723
      }   
 
3724
   } else {
 
3725
      lList *skip_host_list = NULL;
 
3726
      lList *unclear_cqueue_list = NULL;
 
3727
      bool done;
 
3728
      int last_accu_host_slots, last_accu_host_slots_qend;
 
3729
 
 
3730
      if (use_category->use_category) {
 
3731
         skip_host_list = lGetList(use_category->cache, CCT_ignore_hosts);
 
3732
      }   
 
3733
  
 
3734
      accu_host_slots = accu_host_slots_qend = 0;
 
3735
      have_master_host = have_master_host_qend = false;
 
3736
      allocation_rule = sge_pe_slots_per_host(a->pe, a->slots);
 
3737
      minslots = ALLOC_RULE_IS_BALANCED(allocation_rule)?allocation_rule:1;
 
3738
 
 
3739
      {
 
3740
         u_long32 host_seq_no = 0;
 
3741
         const char *eh_name;
 
3742
         lListElem *qep;
 
3743
 
 
3744
         if (a->is_soft) {
 
3745
            a->soft_violations = 0;
 
3746
            for_each (qep, a->queue_list) {
 
3747
               lSetUlong(qep, QU_soft_violation, 0);
 
3748
               if (!(hep = host_list_locate(a->host_list, lGetHost(qep, QU_qhostname))))
 
3749
                  continue;
 
3750
               get_soft_violations(a, hep, qep);
 
3751
               DPRINTF(("EVALUATE: %s soft violations %d\n", lGetString(qep, QU_full_name), lGetUlong(qep, QU_soft_violation)));
 
3752
            }
 
3753
            if (sconf_get_queue_sort_method() == QSM_LOAD)
 
3754
               lPSortList(a->queue_list, "%I+ %I+ %I+", QU_soft_violation, QU_host_seq_no, QU_seq_no);
 
3755
            else
 
3756
               lPSortList(a->queue_list, "%I+ %I+ %I+", QU_soft_violation, QU_seq_no, QU_host_seq_no);
 
3757
         } else {
 
3758
            if (sconf_get_queue_sort_method() == QSM_LOAD)
 
3759
               lPSortList(a->queue_list, "%I+ %I+", QU_host_seq_no, QU_seq_no);
 
3760
            else
 
3761
               lPSortList(a->queue_list, "%I+ %I+", QU_seq_no, QU_host_seq_no);
 
3762
         }
 
3763
 
 
3764
         for_each (hep, a->host_list)
 
3765
            lSetUlong(hep, EH_seq_no, -1);
 
3766
 
 
3767
         for_each (qep, a->queue_list) {
 
3768
            DPRINTF(("AFTER SORT: %s soft violations %d\n", lGetString(qep, QU_full_name), lGetUlong(qep, QU_soft_violation)));
 
3769
            eh_name = lGetHost(qep, QU_qhostname);
 
3770
            if (!(hep = host_list_locate(a->host_list, eh_name)))
 
3771
               continue;
 
3772
            if (lGetUlong(hep, EH_seq_no) == -1)
 
3773
               lSetUlong(hep, EH_seq_no, host_seq_no++);
 
3774
         }
 
3775
         lPSortList(a->host_list, "%I+", EH_seq_no);
 
3776
      }
 
3777
      done = false;
 
3778
 
 
3779
      do {
 
3780
         last_accu_host_slots = accu_host_slots;
 
3781
         last_accu_host_slots_qend = accu_host_slots_qend;
 
3782
 
 
3783
         for_each (hep, a->host_list) {
 
3784
 
 
3785
            int hslots = 0, hslots_qend = 0;
 
3786
            const char *eh_name = lGetHost(hep, EH_name);
 
3787
 
 
3788
            if (!strcasecmp(eh_name, SGE_GLOBAL_NAME) || !strcasecmp(eh_name, SGE_TEMPLATE_NAME)) {
 
3789
               continue;
 
3790
            }   
 
3791
 
 
3792
            /* this host does not work for this category, skip it */
 
3793
            if (skip_host_list && lGetElemStr(skip_host_list, CTI_name, eh_name)){
 
3794
               continue;
 
3795
            }
 
3796
            if (lGetElemStr(a->skip_host_list, CTI_name, eh_name)){
 
3797
               continue;
 
3798
            }
 
3799
 
 
3800
            /* 
 
3801
             * do not perform expensive checks for this host if there 
 
3802
             * is not at least one free queue residing at this host:
 
3803
             * see if there are queues which are not disbaled/suspended/calender;
 
3804
             * which have at least one free slot, which are not unknown, several alarms
 
3805
             */
 
3806
 
 
3807
            if (lGetElemHost(a->queue_list, QU_qhostname, eh_name)) {
 
3808
 
 
3809
               parallel_tag_hosts_queues(a, hep, &hslots, &hslots_qend, 
 
3810
                   &suited_as_master_host, use_category, &unclear_cqueue_list);
 
3811
 
 
3812
               if (hslots >= minslots) {
 
3813
                  /* Now RQ limit debitation can be performed for each queue instance based on QU_tag.
 
3814
                     While considering allocation_rule and master queue demand we try to get as 
 
3815
                     much from each queue as needed, but not more than 'maxslots'. When we are through 
 
3816
                     all queue instances and got not even 'minslots' the slots must be undebited. */
 
3817
                  bool got_master_queue = false;
 
3818
                  lListElem *qep;
 
3819
                  int rqs_hslots = 0, maxslots, slots, slots_qend;
 
3820
 
 
3821
                  /* still broken for cases where round robin requires multiple rounds */
 
3822
                  if (ALLOC_RULE_IS_BALANCED(allocation_rule))
 
3823
                     maxslots = allocation_rule;
 
3824
                  else if (allocation_rule == ALLOC_RULE_FILLUP)
 
3825
                     maxslots = a->slots - accu_host_slots; 
 
3826
                  else /* ALLOC_RULE_ROUNDROBIN */
 
3827
                     maxslots = 1;
 
3828
 
 
3829
                  /* debit on RQS limits */
 
3830
                  for_each (qep, a->queue_list) {
 
3831
                     const char *qname = lGetString(qep, QU_full_name);
 
3832
 
 
3833
                     if (sge_hostcmp(eh_name, lGetHost(qep, QU_qhostname)))
 
3834
                        continue;
 
3835
 
 
3836
                     DPRINTF(("tagged: %d maxslots: %d rqs_hslots: %d\n", (int)lGetUlong(qep, QU_tag), maxslots, rqs_hslots));
 
3837
                     DPRINTF(("SLOT HARVESTING: %s soft violations: %d master: %d\n", 
 
3838
                           lGetString(qep, QU_full_name), (int)lGetUlong(qep, QU_soft_violation), (int)lGetUlong(qep, QU_tagged4schedule)));
 
3839
 
 
3840
                     /* how much is still needed */
 
3841
                     slots = MIN(lGetUlong(qep, QU_tag), maxslots - rqs_hslots);
 
3842
 
 
3843
                     if (need_master_host) {
 
3844
                        /* care for slave tasks assignments of -masterq jobs */
 
3845
                        if (!have_master_host && !got_master_queue && lGetUlong(qep, QU_tagged4schedule)==0 
 
3846
                             && accu_host_slots + rqs_hslots + slots == a->slots)
 
3847
                              slots--;
 
3848
                        /* care for master tasks assignments of -masterq jobs */
 
3849
                        if (lGetUlong(qep, QU_tagged4schedule)==1) {
 
3850
                           if (!have_master_host && !got_master_queue)
 
3851
                              slots = MIN(slots, 1);
 
3852
                           else
 
3853
                              slots = 0;
 
3854
                        }
 
3855
                     }
 
3856
 
 
3857
                     slots_qend = 0;
 
3858
                     if (lGetUlong(a->job, JB_ar)==0 && !a->is_advance_reservation) {
 
3859
                        DPRINTF(("trying to debit %d slots in queue "SFQ"\n", slots, qname));
 
3860
                        parallel_check_and_debit_rqs_slots(a, eh_name, lGetString(qep, QU_qname), 
 
3861
                              &slots, &slots_qend, &rule_name, &rue_name, &limit_name);
 
3862
                        DPRINTF(("could debiting %d slots in queue "SFQ"\n", slots, qname));
 
3863
                     }
 
3864
 
 
3865
                     if (slots > 0) {
 
3866
 
 
3867
                        /* add gdil element for this queue */
 
3868
                        if (!(gdil_ep=lGetElemStr(a->gdil, JG_qname, qname))) {
 
3869
                           gdil_ep = lAddElemStr(&(a->gdil), JG_qname, qname, JG_Type);
 
3870
                           lSetUlong(gdil_ep, JG_qversion, lGetUlong(qep, QU_version));
 
3871
                           lSetHost(gdil_ep, JG_qhostname, eh_name);
 
3872
                           lSetUlong(gdil_ep, JG_slots, slots);
 
3873
 
 
3874
                           /* master queue must be at first position */
 
3875
                           if (need_master_host && !have_master_host && lGetUlong(qep, QU_tagged4schedule)==1) {
 
3876
                              lDechainElem(a->gdil, gdil_ep);
 
3877
                              lInsertElem(a->gdil, NULL, gdil_ep);
 
3878
                              got_master_queue = true;
 
3879
                           }
 
3880
                        } else {
 
3881
                           lAddUlong(gdil_ep, JG_slots, slots);
 
3882
                        }
 
3883
                        if (a->is_soft)
 
3884
                           a->soft_violations += slots * lGetUlong(qep, QU_soft_violation);
 
3885
                     }
 
3886
                     lSetUlong(qep, QU_tag, slots);
 
3887
 
 
3888
                     rqs_hslots += slots;
 
3889
 
 
3890
                     if (rqs_hslots == maxslots)
 
3891
                        break;
 
3892
                  }
 
3893
 
 
3894
                  if (rqs_hslots < minslots) {
 
3895
                     const void *iter = NULL;
 
3896
                     DPRINTF(("reverting debitation since "SFQ" gets us only %d slots while min. %d are needed\n",
 
3897
                           eh_name, rqs_hslots, minslots));
 
3898
                        
 
3899
                     /* must revert all RQS debitations */
 
3900
                     for (qep = lGetElemHostFirst(a->queue_list, QU_qhostname, eh_name, &iter); qep;
 
3901
                          qep = lGetElemHostNext(a->queue_list, QU_qhostname, eh_name, &iter)) {
 
3902
                        slots = lGetUlong(qep, QU_tag);
 
3903
                        if (slots != 0) {
 
3904
                           if (lGetUlong(a->job, JB_ar)==0 && !a->is_advance_reservation) {
 
3905
                              parallel_revert_rqs_slot_debitation(a, eh_name, lGetString(qep, QU_qname), 
 
3906
                                    slots, 0, &rule_name, &rue_name, &limit_name);
 
3907
                           }
 
3908
                           if ((gdil_ep=lGetElemStr(a->gdil, JG_qname, lGetString(qep, QU_full_name)))) {
 
3909
                              if (lGetUlong(gdil_ep, JG_slots) - slots != 0)
 
3910
                                 lSetUlong(gdil_ep, JG_slots, lGetUlong(gdil_ep, JG_slots) - slots);
 
3911
                              else
 
3912
                                 lDelElemStr(&(a->gdil), JG_qname, lGetString(qep, QU_full_name));
 
3913
                           }
 
3914
                           a->soft_violations -= slots * lGetUlong(qep, QU_soft_violation);
 
3915
                           lSetUlong(qep, QU_tag, 0);
 
3916
                        }
 
3917
                     }
 
3918
                     hslots = 0;
 
3919
                     suited_as_master_host = false;
 
3920
                  } else {
 
3921
                     if (got_master_queue)
 
3922
                        suited_as_master_host = true;
 
3923
                     accu_host_slots += rqs_hslots;
 
3924
                  }
 
3925
               }
 
3926
 
 
3927
               if ( hslots_qend >= minslots && a->care_reservation && !a->is_reservation) {
 
3928
                  lListElem *qep;
 
3929
                  bool got_master_queue = false;
 
3930
                  int rqs_hslots = 0, maxslots, slots, slots_qend;
 
3931
 
 
3932
                  /* still broken for cases where round robin requires multiple rounds */
 
3933
                  if (ALLOC_RULE_IS_BALANCED(allocation_rule))
 
3934
                     maxslots = allocation_rule;
 
3935
                  else if (allocation_rule == ALLOC_RULE_FILLUP)
 
3936
                     maxslots = a->slots - accu_host_slots_qend; 
 
3937
                  else /* ALLOC_RULE_ROUNDROBIN */
 
3938
                     maxslots = 1; 
 
3939
                  
 
3940
                  /* debit on RQS limits */
 
3941
                  for_each (qep, a->queue_list) {
 
3942
                     if (sge_hostcmp(eh_name, lGetHost(qep, QU_qhostname)))
 
3943
                        continue;
 
3944
 
 
3945
                     slots = 0;
 
3946
                     slots_qend = MIN(lGetUlong(qep, QU_tag_qend), maxslots - rqs_hslots);
 
3947
 
 
3948
                     if (need_master_host) {
 
3949
                        /* care for slave tasks assignments of -masterq jobs */
 
3950
                        if (!have_master_host_qend && !got_master_queue && lGetUlong(qep, QU_tagged4schedule)==0
 
3951
                            && accu_host_slots_qend + rqs_hslots + slots_qend == a->slots)
 
3952
                           slots_qend--;
 
3953
                        /* care for master tasks assignments of -masterq jobs */
 
3954
                        if (need_master_host && lGetUlong(qep, QU_tagged4schedule)==1) {
 
3955
                           if (!have_master_host_qend && !got_master_queue)
 
3956
                              slots_qend = MIN(slots_qend, 1);
 
3957
                           else
 
3958
                              slots_qend = 0;
 
3959
                        }
 
3960
                     }
 
3961
 
 
3962
                     if (lGetUlong(a->job, JB_ar)==0 && !a->is_advance_reservation) {
 
3963
                        DPRINTF(("trying to debit %d slots_qend in queue "SFQ"\n", slots_qend, lGetString(qep, QU_full_name)));
 
3964
                        parallel_check_and_debit_rqs_slots(a, eh_name, lGetString(qep, QU_qname), 
 
3965
                              &slots, &slots_qend, &rule_name, &rue_name, &limit_name);
 
3966
                        DPRINTF(("could debiting %d slots_qend in queue "SFQ"\n", slots_qend, lGetString(qep, QU_full_name)));
 
3967
                     }
 
3968
                     lSetUlong(qep, QU_tag_qend, slots_qend);
 
3969
                     rqs_hslots += slots_qend;
 
3970
 
 
3971
                     if (rqs_hslots == maxslots)
 
3972
                        break;
 
3973
                  }
 
3974
                  if (rqs_hslots < minslots) {
 
3975
                     const void *iter = NULL;
 
3976
                     DPRINTF(("reverting debitation since "SFQ" gets us only %d slots while min. %d are needed\n",
 
3977
                           eh_name, rqs_hslots, minslots));
 
3978
                        
 
3979
                     /* must revert all RQS debitations */
 
3980
                     for (qep = lGetElemHostFirst(a->queue_list, QU_qhostname, eh_name, &iter); qep;
 
3981
                          qep = lGetElemHostNext(a->queue_list, QU_qhostname, eh_name, &iter)) {
 
3982
                        slots_qend = lGetUlong(qep, QU_tag_qend); 
 
3983
                        if (slots_qend != 0) {
 
3984
                           if (lGetUlong(a->job, JB_ar)==0 && !a->is_advance_reservation)
 
3985
                              parallel_revert_rqs_slot_debitation(a, eh_name, lGetString(qep, QU_qname), 
 
3986
                                    0, slots_qend, &rule_name, &rue_name, &limit_name);
 
3987
                           lSetUlong(qep, QU_tag_qend, 0);
 
3988
                        }
 
3989
                     }
 
3990
                     hslots_qend = 0;
 
3991
                  } else {
 
3992
                     if (got_master_queue)
 
3993
                        suited_as_master_host_qend = true;
 
3994
                     accu_host_slots_qend += rqs_hslots;
 
3995
                  }
 
3996
               }
 
3997
 
 
3998
               /* tag full amount or zero */
 
3999
               have_master_host |= suited_as_master_host;
 
4000
               have_master_host_qend |= suited_as_master_host_qend;
 
4001
            }
 
4002
 
 
4003
            /* mark host as not suitable */
 
4004
            /* at least when accu_host_slots and accu_host_slots_qend < a->slots */
 
4005
            /* and only, if modify category is set */
 
4006
            if (skip_host_list &&  use_category->mod_category ) {
 
4007
               if (hslots < minslots && hslots_qend < minslots) {
 
4008
                  lAddElemStr(&skip_host_list, CTI_name, eh_name, CTI_Type);
 
4009
               }
 
4010
            }
 
4011
 
 
4012
            /* exit is possible when we (a) got the full slot amount or 
 
4013
               (b) got full slot_qend amount and know full slot amount is not achievable anymore */
 
4014
            if ((accu_host_slots >= a->slots && (!need_master_host || have_master_host)) &&
 
4015
                (!a->care_reservation || a->is_reservation || 
 
4016
                 (accu_host_slots_qend >= a->slots && (!need_master_host || have_master_host_qend)))) {
 
4017
               DPRINTF(("WE ARE THROUGH!\n"));
 
4018
               done = true;
 
4019
               break;
 
4020
            }
 
4021
 
 
4022
            /* no need to collect further when slots_qend are complete */
 
4023
            if (a->care_reservation && accu_host_slots_qend >= a->slots && (!need_master_host || have_master_host_qend))
 
4024
               a->care_reservation = false;
 
4025
 
 
4026
         } /* for each host */
 
4027
 
 
4028
      } while (allocation_rule == ALLOC_RULE_ROUNDROBIN && !done && 
 
4029
            (last_accu_host_slots != accu_host_slots || last_accu_host_slots_qend != accu_host_slots_qend));
 
4030
 
 
4031
      lFreeList(&unclear_cqueue_list);
 
4032
 
 
4033
      if (accu_host_slots >= a->slots && 
 
4034
         (!need_master_host || have_master_host)) {
 
4035
         /* stop looking for smaller slot amounts */
 
4036
         DPRINTF(("-------------->      BINGO %d slots %s at specified time <--------------\n", 
 
4037
               a->slots, need_master_host?"plus master host":""));
 
4038
         best_result = DISPATCH_OK;
 
4039
      } else if (accu_host_slots_qend >= a->slots && (!need_master_host || have_master_host)) {
 
4040
         DPRINTF(("-------------->            %d slots %s later             <--------------\n", 
 
4041
               a->slots, need_master_host?"plus master host":""));
 
4042
         best_result = DISPATCH_NOT_AT_TIME;
 
4043
      } else {
 
4044
         DPRINTF(("-------------->   NEVER ONLY %d but %d needed              <--------------\n", 
 
4045
               accu_host_slots, a->slots));
 
4046
         best_result = DISPATCH_NEVER_CAT;
 
4047
      }
 
4048
 
 
4049
      *available_slots = accu_host_slots;
 
4050
 
 
4051
      if (rmon_condition(xaybzc, INFOPRINT)) {
 
4052
         switch (best_result) {
 
4053
         case DISPATCH_OK:
 
4054
            DPRINTF(("COMPREHSENSIVE ASSIGNMENT(%d) returns "sge_u32"\n", 
 
4055
                  a->slots, a->start));
 
4056
            break;
 
4057
         case DISPATCH_NOT_AT_TIME:
 
4058
            DPRINTF(("COMPREHSENSIVE ASSIGNMENT(%d) returns <later>\n", 
 
4059
                  a->slots));
 
4060
            break;
 
4061
         case DISPATCH_NEVER_CAT:
 
4062
            DPRINTF(("COMPREHSENSIVE ASSIGNMENT(%d) returns <category_never>\n", 
 
4063
                  a->slots));
 
4064
            break;
 
4065
         case DISPATCH_NEVER_JOB:
 
4066
            DPRINTF(("COMPREHSENSIVE ASSIGNMENT(%d) returns <job_never>\n", 
 
4067
                  a->slots));
 
4068
            break;
 
4069
         default:
 
4070
            DPRINTF(("!!!!!!!! COMPREHSENSIVE ASSIGNMENT(%d) returns unexpected %d\n", 
 
4071
                  best_result));
 
4072
            break;
 
4073
         }
 
4074
      }
 
4075
   } 
 
4076
 
 
4077
   sge_dstring_free(&rule_name);
 
4078
   sge_dstring_free(&rue_name);
 
4079
   sge_dstring_free(&limit_name);
 
4080
 
 
4081
   if (use_category->use_category) {  
 
4082
      lList *temp = schedd_mes_get_tmp_list();
 
4083
      if (temp){    
 
4084
         lSetList(use_category->cache, CCT_job_messages, lCopyList(NULL, temp));
 
4085
       }
 
4086
   }
 
4087
 
 
4088
   if (best_result != DISPATCH_OK) {
 
4089
      lFreeList(&(a->gdil));
 
4090
   }
 
4091
 
 
4092
   DRETURN(best_result);
 
4093
}
 
4094
 
 
4095
 
 
4096
/****** sge_select_queue/parallel_host_slots() ******************************
 
4097
*  NAME
 
4098
*     parallel_host_slots() -- Return host slots available at time period
 
4099
*
 
4100
*  SYNOPSIS
 
4101
*  FUNCTION
 
4102
*     The maximum amount available at the host for the specified time period
 
4103
*     is determined. 
 
4104
*
 
4105
*
 
4106
*  INPUTS
 
4107
*
 
4108
*  RESULT
 
4109
*******************************************************************************/
 
4110
static dispatch_t 
 
4111
parallel_host_slots(sge_assignment_t *a, int *slots, int *slots_qend, 
 
4112
      lListElem *hep, bool allow_non_requestable) {
 
4113
 
 
4114
   int hslots = 0, hslots_qend = 0;
 
4115
   const char *eh_name;
 
4116
   dispatch_t result = DISPATCH_NEVER_CAT;
 
4117
   lList *hard_requests = lGetList(a->job, JB_hard_resource_list);
 
4118
   lList *load_list = lGetList(hep, EH_load_list); 
 
4119
   lList *config_attr = lGetList(hep, EH_consumable_config_list);
 
4120
   lList *actual_attr = lGetList(hep, EH_resource_utilization);
 
4121
   double lc_factor = 0;
 
4122
 
 
4123
   DENTER(TOP_LAYER, "parallel_host_slots");
 
4124
 
 
4125
   eh_name = lGetHost(hep, EH_name);
 
4126
 
 
4127
   clear_resource_tags(hard_requests, HOST_TAG);
 
4128
 
 
4129
   if (a->pi)
 
4130
      a->pi->par_hstat++;
 
4131
 
 
4132
   if (!(qref_list_eh_rejected(lGetList(a->job, JB_hard_queue_list), eh_name, a->hgrp_list) && 
 
4133
        qref_list_eh_rejected(lGetList(a->job, JB_master_hard_queue_list), eh_name, a->hgrp_list)) &&
 
4134
               sge_host_match_static(a->job, a->ja_task, hep, a->centry_list, a->acl_list) == DISPATCH_OK) {
 
4135
 
 
4136
      /* cause load be raised artificially to reflect load correction when
 
4137
         checking job requests */
 
4138
      if (lGetPosViaElem(hep, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
4139
         u_long32 ulc_factor;
 
4140
         if ((ulc_factor=lGetUlong(hep, EH_load_correction_factor))) {
 
4141
            lc_factor = ((double)ulc_factor)/100;
 
4142
         }      
 
4143
      }
 
4144
 
 
4145
      if (a->pi)
 
4146
         a->pi->par_hdyn++;
 
4147
 
 
4148
      result = parallel_rc_slots_by_time(a, hard_requests, &hslots, &hslots_qend, 
 
4149
            config_attr, actual_attr, load_list, false, NULL, 
 
4150
               DOMINANT_LAYER_HOST, lc_factor, HOST_TAG, false, eh_name, false);
 
4151
 
 
4152
      if (hslots > 0) {
 
4153
         const void *iterator = NULL;
 
4154
         lListElem *gdil;
 
4155
         int t_max = parallel_max_host_slots(a, hep);
 
4156
         if (t_max<hslots) {
 
4157
            DPRINTF(("\tparallel_host_slots(%s) threshold load adjustment reduces slots"
 
4158
                  " from %d to %d\n", eh_name, hslots, t_max));
 
4159
            hslots = t_max;
 
4160
         }
 
4161
 
 
4162
         for (gdil = lGetElemHostFirst(a->gdil, JG_qhostname, eh_name, &iterator); 
 
4163
              gdil != NULL;
 
4164
              gdil = lGetElemHostNext(a->gdil, JG_qhostname, eh_name, &iterator)) {
 
4165
            hslots -= lGetUlong(gdil, JG_slots);
 
4166
         }
 
4167
      }
 
4168
   }
 
4169
 
 
4170
   *slots = hslots;
 
4171
   *slots_qend = hslots_qend;
 
4172
 
 
4173
   if (result == DISPATCH_OK) {
 
4174
      DPRINTF(("\tparallel_host_slots(%s) returns %d/%d\n", eh_name, hslots, hslots_qend));
 
4175
   } 
 
4176
   else {
 
4177
      DPRINTF(("\tparallel_host_slots(%s) returns <error>\n", eh_name));
 
4178
   }
 
4179
 
 
4180
   DRETURN(result); 
 
4181
}
 
4182
 
 
4183
/****** sge_select_queue/parallel_tag_hosts_queues() **********************************
 
4184
*  NAME
 
4185
*     parallel_tag_hosts_queues() -- Determine host slots and tag queue(s) accordingly
 
4186
*
 
4187
*  SYNOPSIS
 
4188
*
 
4189
*  FUNCTION
 
4190
*     For a particular job the maximum number of slots that could be served 
 
4191
*     at that host is determined in accordance with the allocation rule and
 
4192
*     returned. The time of the assignment can be either DISPATCH_TIME_NOW
 
4193
*     or a specific time, but never DISPATCH_TIME_QUEUE_END.
 
4194
*
 
4195
*     In those cases when the allocation rule allows more than one slot be 
 
4196
*     served per host it is necessary to also consider per queue possibly 
 
4197
*     specified load thresholds. This is because load is global/per host 
 
4198
*     concept while load thresholds are a queue attribute.
 
4199
*
 
4200
*     In those cases when the allocation rule gives us neither a fixed amount 
 
4201
*     of slots required nor an upper limit for the number per host slots (i.e. 
 
4202
*     $fill_up and $round_robin) we must iterate through all slot numbers from 
 
4203
*     1 to the maximum number of slots "total_slots" and check with each slot
 
4204
*     amount whether we can get it or not. Iteration stops when we can't get 
 
4205
*     more slots the host based on the queue limitations and load thresholds. 
 
4206
*
 
4207
*     As long as only one single queue at the host is eligible for the job the
 
4208
*     it is sufficient to check with each iteration whether the corresponding 
 
4209
*     number of slots can be served by the host and it's queue or not. The 
 
4210
*     really sick case however is when multiple queues are eligable for a host: 
 
4211
*     Here we have to determine in each iteration step also the maximum number 
 
4212
*     of slots each queue could get us by doing a per queue iteration from the 
 
4213
*     1 up to the maximum number of slots we're testing. The optimization in 
 
4214
*     effect here is to check always only if we could get more slots than with
 
4215
*     the former per host slot amount iteration. 
 
4216
*
 
4217
*  INPUTS
 
4218
*     sge_assignment_t *a          -
 
4219
*     lListElem *hep               - current host
 
4220
*     lListElem *global            - global host
 
4221
*     int *slots                   - out: # free slots
 
4222
*     int *slots_qend              - out: # free slots in the far far future
 
4223
*     int global_soft_violations   - # of global soft violations
 
4224
*     bool *master_host            - out: if true, found a master host
 
4225
*     category_use_t *use_category - int/out : how to use the job category
 
4226
*
 
4227
*  RESULT
 
4228
*     static dispatch_t -  0 ok got an assignment
 
4229
*                          1 no assignment at the specified time
 
4230
*                         -1 assignment will never be possible for all jobs of that category
 
4231
*                         -2 assignment will never be possible for that particular job
 
4232
*
 
4233
*  NOTES
 
4234
*     MT-NOTE: parallel_tag_hosts_queues() is not MT safe 
 
4235
*******************************************************************************/
 
4236
static dispatch_t
 
4237
parallel_tag_hosts_queues(sge_assignment_t *a, lListElem *hep, int *slots, int *slots_qend, 
 
4238
                          bool *master_host, category_use_t *use_category, 
 
4239
                          lList **unclear_cqueue_list) 
 
4240
{
 
4241
   bool suited_as_master_host = false;
 
4242
   int min_host_slots = 1;
 
4243
   int max_host_slots = a->slots;
 
4244
   int accu_queue_slots, accu_queue_slots_qend;
 
4245
   int qslots, qslots_qend;
 
4246
   int hslots = 0;
 
4247
   int hslots_qend = 0;
 
4248
   const char *cqname, *qname, *eh_name = lGetHost(hep, EH_name);
 
4249
   lListElem *qep, *next_queue; 
 
4250
   dispatch_t result = DISPATCH_OK;
 
4251
   const void *queue_iterator = NULL;
 
4252
   int allocation_rule; 
 
4253
   
 
4254
   DENTER(TOP_LAYER, "parallel_tag_hosts_queues");
 
4255
 
 
4256
   allocation_rule = sge_pe_slots_per_host(a->pe, a->slots);
 
4257
 
 
4258
   if (ALLOC_RULE_IS_BALANCED(allocation_rule)) {
 
4259
      min_host_slots = max_host_slots = allocation_rule;
 
4260
   }
 
4261
 
 
4262
   if (lGetUlong(a->job, JB_ar) == 0) {
 
4263
      parallel_host_slots(a, &hslots, &hslots_qend, hep, false);
 
4264
   } else {
 
4265
      lList *config_attr = lGetList(hep, EH_consumable_config_list);
 
4266
      lList *actual_attr = lGetList(hep, EH_resource_utilization);
 
4267
      lList *load_attr = lGetList(hep, EH_load_list);
 
4268
      lList *hard_resource_list = lGetList(a->job, JB_hard_resource_list);
 
4269
      lListElem *rep;
 
4270
      dstring reason = DSTRING_INIT;
 
4271
 
 
4272
      clear_resource_tags(hard_resource_list, HOST_TAG);
 
4273
 
 
4274
      for_each(rep, hard_resource_list) {
 
4275
         const char *attrname = lGetString(rep, CE_name);
 
4276
         lListElem *cplx_el = lGetElemStr(a->centry_list, CE_name, attrname);
 
4277
 
 
4278
         if (lGetBool(cplx_el, CE_consumable)) {
 
4279
            continue;
 
4280
         }
 
4281
         sge_dstring_clear(&reason);
 
4282
         cplx_el = get_attribute(attrname, config_attr, actual_attr, load_attr, a->centry_list, NULL,
 
4283
                  DOMINANT_LAYER_HOST, 0, &reason, false, DISPATCH_TIME_NOW, 0);
 
4284
         if (cplx_el != NULL) {
 
4285
            if (match_static_resource(1, rep, cplx_el, &reason, false, false, false) == DISPATCH_OK) {
 
4286
               lSetUlong(rep, CE_tagged, HOST_TAG); 
 
4287
            }
 
4288
            lFreeElem(&cplx_el);
 
4289
         }
 
4290
      }
 
4291
      sge_dstring_free(&reason);
 
4292
 
 
4293
      {
 
4294
         lListElem *gdil_ep;
 
4295
         const void *iterator = NULL;
 
4296
         lListElem *ar = ar_list_locate(a->ar_list, lGetUlong(a->job, JB_ar));
 
4297
         lList *granted_list = lGetList(ar, AR_granted_slots);
 
4298
 
 
4299
         for (gdil_ep = lGetElemHostFirst(granted_list, JG_qhostname, eh_name, &iterator); 
 
4300
              gdil_ep != NULL;
 
4301
              gdil_ep = lGetElemHostNext(granted_list, JG_qhostname, eh_name, &iterator)) {
 
4302
              hslots += lGetUlong(gdil_ep, JG_slots);
 
4303
         }
 
4304
         hslots_qend = hslots;
 
4305
      }
 
4306
   }
 
4307
 
 
4308
 
 
4309
   DPRINTF(("HOST %s itself (and queue threshold) will get us %d slots (%d later) ... "
 
4310
         "we need %d\n", eh_name, hslots, hslots_qend, min_host_slots));
 
4311
 
 
4312
   hslots      = MIN(hslots,      max_host_slots);
 
4313
   hslots_qend = MIN(hslots_qend, max_host_slots);
 
4314
 
 
4315
 
 
4316
   if (hslots >= min_host_slots || hslots_qend >= min_host_slots) {
 
4317
      lList *skip_queue_list = NULL;
 
4318
      if (use_category->use_category) {
 
4319
         skip_queue_list = lGetList(use_category->cache, CCT_ignore_queues);
 
4320
      }
 
4321
      
 
4322
      accu_queue_slots = accu_queue_slots_qend = 0;
 
4323
 
 
4324
      for (next_queue = lGetElemHostFirst(a->queue_list, QU_qhostname, eh_name, &queue_iterator); 
 
4325
          (qep = next_queue);
 
4326
           next_queue = lGetElemHostNext(a->queue_list, QU_qhostname, eh_name, &queue_iterator)) {
 
4327
 
 
4328
         qname = lGetString(qep, QU_full_name);
 
4329
         cqname = lGetString(qep, QU_qname);
 
4330
 
 
4331
         /* try to foreclose the cluster queue */
 
4332
         if (lGetElemStr(a->skip_cqueue_list, CTI_name, cqname)) {
 
4333
            DPRINTF(("(1) skip cluster queue %s\n", cqname));             
 
4334
            continue;
 
4335
         }
 
4336
 
 
4337
         if (!lGetElemStr(*unclear_cqueue_list, CTI_name, cqname)) {
 
4338
 
 
4339
            if (a->pi)
 
4340
               a->pi->par_cqstat++;
 
4341
            if (cqueue_match_static(cqname, a) != DISPATCH_OK) {
 
4342
               lAddElemStr(&(a->skip_cqueue_list), CTI_name, cqname, CTI_Type);
 
4343
               DPRINTF(("add cluster queue %s to skip list\n", cqname));             
 
4344
               continue;
 
4345
            }
 
4346
            DPRINTF(("cqueue %s is not rejected\n", cqname));
 
4347
            lAddElemStr(unclear_cqueue_list, CTI_name, cqname, CTI_Type);
 
4348
         }
 
4349
 
 
4350
         if (skip_queue_list && lGetElemStr(skip_queue_list, CTI_name, qname)){
 
4351
            DPRINTF(("(2) skip cluster queue %s\n", cqname));             
 
4352
            continue;
 
4353
         }
 
4354
         
 
4355
         DPRINTF(("checking queue %s because cqueue %s is not rejected\n", qname, cqname));
 
4356
         result = parallel_queue_slots(a, qep, &qslots, &qslots_qend, false);
 
4357
 
 
4358
         if (result == DISPATCH_OK && (qslots > 0 || qslots_qend > 0)) {
 
4359
 
 
4360
            /* could this host be a master host */
 
4361
            if (!suited_as_master_host && lGetUlong(qep, QU_tagged4schedule)) {
 
4362
               DPRINTF(("HOST %s can be master host because of queue %s\n", eh_name, qname));    
 
4363
               suited_as_master_host = true; 
 
4364
            }
 
4365
 
 
4366
            DPRINTF(("QUEUE %s TIME: %d + %d -> %d  QEND: %d + %d -> %d (%d soft violations)\n", qname, 
 
4367
                     accu_queue_slots,      qslots,      accu_queue_slots+       qslots, 
 
4368
                     accu_queue_slots_qend, qslots_qend, accu_queue_slots_qend + qslots_qend,
 
4369
                     (int)lGetUlong(qep, QU_soft_violation))); 
 
4370
 
 
4371
            accu_queue_slots      += qslots;
 
4372
            accu_queue_slots_qend += qslots_qend;
 
4373
            lSetUlong(qep, QU_tag, qslots);
 
4374
            lSetUlong(qep, QU_tag_qend, qslots_qend);
 
4375
         } else {
 
4376
            if (skip_queue_list) {
 
4377
               lAddElemStr(&skip_queue_list, CTI_name, qname, CTI_Type);
 
4378
            }         
 
4379
            DPRINTF(("HOST(1.5) %s will get us nothing\n", eh_name)); 
 
4380
         }
 
4381
 
 
4382
      } /* for each queue of the host */
 
4383
 
 
4384
      hslots      = MIN(accu_queue_slots,      hslots);
 
4385
      hslots_qend = MIN(accu_queue_slots_qend, hslots_qend);
 
4386
 
 
4387
      DPRINTF(("HOST %s and it's queues will get us %d slots (%d later) ... we need %d\n", 
 
4388
            eh_name, hslots, hslots_qend, min_host_slots));
 
4389
   }
 
4390
 
 
4391
   *slots       = hslots;
 
4392
   *slots_qend  = hslots_qend;
 
4393
   *master_host = suited_as_master_host;
 
4394
 
 
4395
   DRETURN(DISPATCH_OK);
 
4396
}
 
4397
 
 
4398
/* 
 
4399
 * Determine maximum number of host_slots as limited 
 
4400
 * by queue load thresholds. The maximum only considers
 
4401
 * thresholds with load adjustments
 
4402
 * 
 
4403
 * for each queue Q at this host {
 
4404
 *    for each threshold T of a queue {
 
4405
 *       if compare operator > or >=
 
4406
 *          avail(Q, T) = <threshold - load / adjustment) + 1     
 
4407
 *       else
 
4408
 *          avail(Q, T) = (threshold - load / -adjustMent) + 1
 
4409
 *    }
 
4410
 *    avail(Q) = MIN(all avail(Q, T))
 
4411
 * }
 
4412
 * host_slot_max_by_T = MAX(all min(Q))
 
4413
 */
 
4414
static int 
 
4415
parallel_max_host_slots(sge_assignment_t *a, lListElem *host) {
 
4416
   int avail_h = 0, avail_q;
 
4417
   int avail;
 
4418
   lListElem *next_queue, *qep, *centry = NULL;
 
4419
   lListElem *lv, *lc, *tr, *fv, *cep;
 
4420
   const char *eh_name = lGetHost(host, EH_name);
 
4421
   const void *queue_iterator = NULL;
 
4422
   const char *load_value, *limit_value, *adj_value;
 
4423
   u_long32 type;
 
4424
   bool is_np_adjustment = false;
 
4425
   lList *requests = lGetList(a->job, JB_hard_resource_list);
 
4426
 
 
4427
   DENTER(TOP_LAYER, "parallel_max_host_slots");
 
4428
 
 
4429
   for (next_queue = lGetElemHostFirst(a->queue_list, QU_qhostname, eh_name, &queue_iterator); 
 
4430
       (qep = next_queue);
 
4431
        next_queue = lGetElemHostNext(a->queue_list, QU_qhostname, eh_name, &queue_iterator)) {
 
4432
      lList *load_thresholds = lGetList(qep, QU_load_thresholds);
 
4433
      avail_q = INT_MAX;
 
4434
 
 
4435
      for_each(tr, load_thresholds) {
 
4436
         double load, threshold, adjustment;
 
4437
         const char *name = lGetString(tr, CE_name);
 
4438
         if ((cep = centry_list_locate(a->centry_list, name)) == NULL) {
 
4439
            continue;
 
4440
         }   
 
4441
         
 
4442
         if (!lGetBool(cep, CE_consumable)) { /* work on the load values */
 
4443
            if ((lc = lGetElemStr(a->load_adjustments, CE_name, name)) == NULL) {
 
4444
               continue;
 
4445
            } 
 
4446
            if ((lv=lGetSubStr(host, HL_name, name, EH_load_list)) != NULL) {
 
4447
               load_value = lGetString(lv, HL_value);
 
4448
            }
 
4449
            else if ((lv = lGetSubStr(a->gep, HL_name, name, EH_load_list)) != NULL) {
 
4450
               load_value = lGetString(lv, HL_value);
 
4451
            } 
 
4452
            else {
 
4453
               fv = lGetSubStr(qep, CE_name, name, QU_consumable_config_list);
 
4454
               load_value = lGetString(fv, CE_stringval);
 
4455
            }
 
4456
            adj_value = lGetString(lc, CE_stringval);
 
4457
            is_np_adjustment = true;
 
4458
            adj_value = lGetString(lc, CE_stringval);
 
4459
 
 
4460
         }
 
4461
         else { /* work on a consumable */
 
4462
            
 
4463
            if ((lc = lGetElemStr(requests, CE_name, name)) != NULL) {
 
4464
               adj_value = lGetString(lc, CE_stringval);
 
4465
            }
 
4466
            else { /* is default value */
 
4467
               adj_value = lGetString(cep, CE_default);
 
4468
            }
 
4469
 
 
4470
            if ((centry = get_attribute_by_name(a->gep, host, qep, name, a->centry_list, a->start, a->duration)) == NULL) {
 
4471
                /* no load value, no assigned consumable to queue, host, or global */
 
4472
                DPRINTF(("the consumable "SFN" used in queue "SFN" as load threshold has no instance at queue, host or global level\n", 
 
4473
                         name, lGetString(qep, QU_full_name))); 
 
4474
                DRETURN(0);
 
4475
            }    
 
4476
 
 
4477
            load_value = lGetString(centry, CE_pj_stringval);
 
4478
         }
 
4479
 
 
4480
         limit_value = lGetString(tr, CE_stringval);
 
4481
         type = lGetUlong(cep, CE_valtype);
 
4482
 
 
4483
         /* get the needed values. If the load value is not a number, ignore it */
 
4484
         switch (type) {
 
4485
            case TYPE_INT:
 
4486
            case TYPE_TIM:
 
4487
            case TYPE_MEM:
 
4488
            case TYPE_BOO:
 
4489
            case TYPE_DOUBLE:
 
4490
 
 
4491
               if (!parse_ulong_val(&load, NULL, type, load_value, NULL, 0) ||
 
4492
                   !parse_ulong_val(&threshold, NULL, type, limit_value, NULL, 0) ||
 
4493
                   !parse_ulong_val(&adjustment, NULL, type, adj_value, NULL, 0)) {
 
4494
                   lFreeElem(&centry);
 
4495
                  continue;
 
4496
               }
 
4497
 
 
4498
               break;
 
4499
 
 
4500
            default:
 
4501
               lFreeElem(&centry);
 
4502
               continue;    
 
4503
         }
 
4504
         /* the string in load_value is not needed anymore, we can free the element */
 
4505
         lFreeElem(&centry);
 
4506
 
 
4507
         /* a adjustment of NULL is ignored here. We can dispatch unlimited jobs based
 
4508
            on the load value */
 
4509
         if (adjustment == 0) {
 
4510
            continue;
 
4511
         }
 
4512
 
 
4513
         switch (lGetUlong(cep, CE_relop)) {
 
4514
            case CMPLXEQ_OP :
 
4515
            case CMPLXNE_OP : continue; /* we cannot compute a usefull range */
 
4516
            case CMPLXLT_OP :
 
4517
            case CMPLXLE_OP : adjustment *= -1;
 
4518
               break;
 
4519
         }
 
4520
 
 
4521
         if (is_np_adjustment) {
 
4522
            load_np_value_adjustment(name, host, &adjustment);
 
4523
         }
 
4524
 
 
4525
         /* load alarm is defined in a way, that a host can go with one
 
4526
            used slot into alarm and not that the dispatching prevents
 
4527
            the alarm state. For this behavior we have to add 1 to the
 
4528
            available slots. However, this is not true for consumables
 
4529
            as load threshold*/
 
4530
         avail = (threshold - load)/adjustment;
 
4531
         if (!lGetBool(cep, CE_consumable)) {
 
4532
            avail++;
 
4533
         }
 
4534
         avail_q = MIN(avail, avail_q);         
 
4535
      }
 
4536
 
 
4537
      avail_h = MAX(avail_h, avail_q);
 
4538
   }
 
4539
   DRETURN(avail_h);
 
4540
}
 
4541
 
 
4542
/****** sge_select_queue/sge_sequential_assignment() ***************************
 
4543
*  NAME
 
4544
*     sge_sequential_assignment() -- Make an assignment for a sequential job.
 
4545
*
 
4546
*  SYNOPSIS
 
4547
*     int sge_sequential_assignment(sge_assignment_t *assignment)
 
4548
*
 
4549
*  FUNCTION
 
4550
*     For sequential job assignments all the earliest job start time
 
4551
*     is determined with each queue instance and the earliest one gets
 
4552
*     chosen. Secondary criterion for queue selection minimizing jobs 
 
4553
*     soft requests.
 
4554
*
 
4555
*     The overall behaviour of this function is somewhat dependent on the 
 
4556
*     value that gets passed to assignment->start and whether soft requests 
 
4557
*     were specified with the job: 
 
4558
*
 
4559
*     (1) In case of now assignemnts (DISPATCH_TIME_NOW) only the first queue 
 
4560
*         suitable for jobs without soft requests is tagged. When soft requests 
 
4561
*         are specified all queues must be verified and tagged in order to find 
 
4562
*         the queue that fits best. On success the start time is set 
 
4563
*     
 
4564
*     (2) In case of queue end assignments (DISPATCH_TIME_QUEUE_END) 
 
4565
*
 
4566
*
 
4567
*  INPUTS
 
4568
*     sge_assignment_t *assignment - ??? 
 
4569
*
 
4570
*  RESULT
 
4571
*     int - 0 ok got an assignment + time (DISPATCH_TIME_NOW and DISPATCH_TIME_QUEUE_END)
 
4572
*           1 no assignment at the specified time
 
4573
*          -1 assignment will never be possible for all jobs of that category
 
4574
*          -2 assignment will never be possible for that particular job
 
4575
*
 
4576
*  NOTES
 
4577
*     MT-NOTE: sge_sequential_assignment() is not MT safe 
 
4578
*******************************************************************************/
 
4579
dispatch_t sge_sequential_assignment(sge_assignment_t *a) 
 
4580
{
 
4581
   dispatch_t result;
 
4582
   int old_logging = 0;
 
4583
 
 
4584
   DENTER(TOP_LAYER, "sge_sequential_assignment");
 
4585
 
 
4586
   if (a == NULL) {
 
4587
      DRETURN(DISPATCH_NEVER_CAT);
 
4588
   }
 
4589
 
 
4590
   if (a->is_reservation && !a->is_advance_reservation){
 
4591
      /* turn off messages for reservation scheduling */
 
4592
      old_logging = schedd_mes_get_logging();
 
4593
      schedd_mes_set_logging(0);
 
4594
      schedd_mes_off();
 
4595
   } 
 
4596
 
 
4597
   /* untag all queues */
 
4598
   qinstance_list_set_tag(a->queue_list, 0);
 
4599
 
 
4600
   sequential_update_host_order(a->host_list, a->queue_list);
 
4601
 
 
4602
   if (sconf_get_qs_state() != QS_STATE_EMPTY) {
 
4603
      /*------------------------------------------------------------------
 
4604
       *  There is no need to sort the queues after each dispatch in 
 
4605
       *  case:
 
4606
       *
 
4607
       *    1. The last dispatch was also a sequential job without
 
4608
       *       soft requests. If not then the queues are sorted by
 
4609
       *       other criterions (soft violations, # of tagged slots, 
 
4610
       *       masterq).
 
4611
       *    2. The hosts sort order has not changed since last dispatch.
 
4612
       *       Load correction or consumables in the load formula can
 
4613
       *       change the order of the hosts. We detect changings in the
 
4614
       *       host order by comparing the host sequence number with the
 
4615
       *       sequence number from previous run.
 
4616
       * ------------------------------------------------------------------*/
 
4617
      if (sconf_get_last_dispatch_type() != DISPATCH_TYPE_FAST || sconf_get_host_order_changed()) {
 
4618
         DPRINTF(("SORTING HOSTS!\n"));
 
4619
         if (sconf_get_queue_sort_method() == QSM_LOAD)
 
4620
            lPSortList(a->queue_list, "%I+ %I+", QU_host_seq_no, QU_seq_no);
 
4621
         else
 
4622
            lPSortList(a->queue_list, "%I+ %I+", QU_seq_no, QU_host_seq_no);
 
4623
      }
 
4624
      if (a->is_soft) {
 
4625
         sconf_set_last_dispatch_type(DISPATCH_TYPE_FAST_SOFT_REQ);
 
4626
      }
 
4627
      else {
 
4628
         sconf_set_last_dispatch_type(DISPATCH_TYPE_FAST);
 
4629
      }
 
4630
   }
 
4631
 
 
4632
   result = sequential_tag_queues_suitable4job(a);
 
4633
 
 
4634
   if (result == DISPATCH_OK) {
 
4635
      lListElem *qep;
 
4636
      u_long32 job_start_time = U_LONG32_MAX;
 
4637
      u_long32 min_soft_violations = U_LONG32_MAX;
 
4638
      lListElem *best_queue = NULL;
 
4639
 
 
4640
      if (a->is_reservation) {
 
4641
         for_each (qep, a->queue_list) {
 
4642
            if (lGetUlong(qep, QU_tag) != 0) {
 
4643
               u_long32 temp_job_start_time = lGetUlong(qep, QU_available_at);
 
4644
 
 
4645
               DPRINTF(("    Q: %s "sge_u32" "sge_u32" (jst: "sge_u32")\n", lGetString(qep, QU_full_name), 
 
4646
                        lGetUlong(qep, QU_tag), temp_job_start_time, job_start_time));
 
4647
 
 
4648
               /* earlier start time has higher preference than lower soft violations */
 
4649
               if ((job_start_time > temp_job_start_time) ||
 
4650
                    (a->is_soft && 
 
4651
                        min_soft_violations > lGetUlong(qep, QU_soft_violation) && 
 
4652
                        job_start_time == temp_job_start_time)
 
4653
                  ) {
 
4654
 
 
4655
                  best_queue = qep;
 
4656
                  job_start_time = temp_job_start_time;
 
4657
                  min_soft_violations = lGetUlong(qep, QU_soft_violation);
 
4658
               }
 
4659
            }
 
4660
         }
 
4661
         if (best_queue) {
 
4662
            DPRINTF(("earliest queue \"%s\" at "sge_u32"\n", lGetString(best_queue, QU_full_name), job_start_time));
 
4663
         } else {
 
4664
            DPRINTF(("no earliest queue found!\n"));
 
4665
         }
 
4666
      } else {
 
4667
         if (a->is_soft) {
 
4668
            if (sconf_get_queue_sort_method() == QSM_LOAD)
 
4669
               lPSortList(a->queue_list, "%I+ %I+ %I+", QU_soft_violation, QU_host_seq_no, QU_seq_no);
 
4670
            else
 
4671
               lPSortList(a->queue_list, "%I+ %I+ %I+", QU_soft_violation, QU_seq_no, QU_host_seq_no);
 
4672
         }
 
4673
 
 
4674
         for_each (qep, a->queue_list) {
 
4675
            if (lGetUlong(qep, QU_tag)) {
 
4676
               job_start_time = lGetUlong(qep, QU_available_at);
 
4677
               best_queue = qep;
 
4678
               break;
 
4679
            }
 
4680
         }
 
4681
      }
 
4682
 
 
4683
      if (!best_queue) {
 
4684
         DRETURN(DISPATCH_NEVER_CAT); /* should never happen */
 
4685
      }
 
4686
      {
 
4687
         lListElem *gdil_ep;
 
4688
         lList *gdil = NULL;
 
4689
         const char *qname = lGetString(best_queue, QU_full_name);
 
4690
         const char *eh_name = lGetHost(best_queue, QU_qhostname);
 
4691
 
 
4692
         DPRINTF((sge_u32": 1 slot in queue %s user %s %s for "sge_u32"\n",
 
4693
            a->job_id, qname, a->user? a->user:"<unknown>", 
 
4694
                  !a->is_reservation?"scheduled":"reserved", job_start_time));
 
4695
 
 
4696
         gdil_ep = lAddElemStr(&gdil, JG_qname, qname, JG_Type);
 
4697
         lSetUlong(gdil_ep, JG_qversion, lGetUlong(best_queue, QU_version));
 
4698
         lSetHost(gdil_ep, JG_qhostname, eh_name);
 
4699
         lSetUlong(gdil_ep, JG_slots, 1);
 
4700
 
 
4701
         if (!a->is_reservation) {
 
4702
            sconf_inc_fast_jobs();
 
4703
         }
 
4704
 
 
4705
         lFreeList(&(a->gdil));
 
4706
         a->gdil = gdil;
 
4707
         if (a->start == DISPATCH_TIME_QUEUE_END) {
 
4708
            a->start = job_start_time;
 
4709
         }   
 
4710
   
 
4711
         result = DISPATCH_OK;
 
4712
      }
 
4713
   }
 
4714
 
 
4715
   switch (result) {
 
4716
   case DISPATCH_OK:
 
4717
      DPRINTF(("SEQUENTIAL ASSIGNMENT("sge_u32"."sge_u32") returns <time> "sge_u32"\n", 
 
4718
            a->job_id, a->ja_task_id, a->start));
 
4719
      break;
 
4720
   case DISPATCH_NOT_AT_TIME:
 
4721
      DPRINTF(("SEQUENTIAL ASSIGNMENT("sge_u32"."sge_u32") returns <later>\n", 
 
4722
            a->job_id, a->ja_task_id)); 
 
4723
      break;
 
4724
   case DISPATCH_NEVER_CAT:
 
4725
      DPRINTF(("SEQUENTIAL ASSIGNMENT("sge_u32"."sge_u32") returns <category_never>\n", 
 
4726
            a->job_id, a->ja_task_id)); 
 
4727
      break;
 
4728
   case DISPATCH_NEVER_JOB:
 
4729
      DPRINTF(("SEQUENTIAL ASSIGNMENT("sge_u32"."sge_u32") returns <job_never>\n", 
 
4730
            a->job_id, a->ja_task_id)); 
 
4731
      break;
 
4732
   case DISPATCH_MISSING_ATTR:    
 
4733
   default:
 
4734
      DPRINTF(("!!!!!!!! SEQUENTIAL ASSIGNMENT("sge_u32"."sge_u32") returns unexpected %d\n", 
 
4735
            a->job_id, a->ja_task_id, result));
 
4736
      break;
 
4737
   }
 
4738
 
 
4739
   if (a->is_reservation && !a->is_advance_reservation) {
 
4740
      schedd_mes_set_logging(old_logging);
 
4741
      schedd_mes_on();
 
4742
   }   
 
4743
 
 
4744
   DRETURN(result);
 
4745
}
 
4746
 
 
4747
/*------------------------------------------------------------------
 
4748
 *  FAST TRACK FOR SEQUENTIAL JOBS WITHOUT A SOFT REQUEST 
 
4749
 *
 
4750
 *  It is much faster not to review slots in a comprehensive fashion 
 
4751
 *  for jobs of this type.
 
4752
 * ------------------------------------------------------------------*/
 
4753
static int sequential_update_host_order(lList *host_list, lList *queues)
 
4754
{
 
4755
   lListElem *hep, *qep;
 
4756
   double previous_load = 0;
 
4757
   int previous_load_inited = 0;
 
4758
   int host_seqno = 0;
 
4759
   const char *eh_name;
 
4760
   const void *iterator = NULL;
 
4761
   bool host_order_changed = false;
 
4762
 
 
4763
   DENTER(TOP_LAYER, "sequential_update_host_order");
 
4764
 
 
4765
   if (!sconf_get_host_order_changed()) {
 
4766
      DRETURN(0);
 
4767
   }
 
4768
 
 
4769
   sconf_set_host_order_changed(host_order_changed);
 
4770
 
 
4771
   for_each (hep, host_list) { /* in share/load order */
 
4772
 
 
4773
      /* figure out host_seqno
 
4774
         in case the load of two hosts is equal this
 
4775
         must be also reflected by the sequence number */
 
4776
      if (!previous_load_inited) {
 
4777
         host_seqno = 0;
 
4778
         previous_load = lGetDouble(hep, EH_sort_value);
 
4779
         previous_load_inited = 1;
 
4780
      } else {
 
4781
         if (previous_load < lGetDouble(hep, EH_sort_value)) {
 
4782
            host_seqno++;
 
4783
            previous_load = lGetDouble(hep, EH_sort_value);
 
4784
         }
 
4785
      }
 
4786
 
 
4787
      /* set host_seqno for all queues of this host */
 
4788
      eh_name = lGetHost(hep, EH_name);
 
4789
      
 
4790
      qep = lGetElemHostFirst(queues, QU_qhostname, eh_name, &iterator); 
 
4791
      while (qep != NULL) {
 
4792
          lSetUlong(qep, QU_host_seq_no, host_seqno);
 
4793
          qep = lGetElemHostNext(queues, QU_qhostname, eh_name, &iterator);
 
4794
      }
 
4795
 
 
4796
      /* detect whether host_seqno has changed since last dispatch operation */
 
4797
      if (host_seqno != lGetUlong(hep, EH_seq_no)) {
 
4798
         DPRINTF(("HOST SORT ORDER CHANGED FOR HOST %s FROM %d to %d\n", 
 
4799
                  eh_name, lGetUlong(hep, EH_seq_no), host_seqno));
 
4800
         host_order_changed = true;
 
4801
         lSetUlong(hep, EH_seq_no, host_seqno);
 
4802
      }
 
4803
   }
 
4804
 
 
4805
   sconf_set_host_order_changed(host_order_changed);
 
4806
 
 
4807
   DRETURN(0);
 
4808
}
 
4809
 
 
4810
/****** sge_select_queue/parallel_assignment() *****************************
 
4811
*  NAME
 
4812
*     parallel_assignment() -- Can we assign with a fixed PE/slot/time
 
4813
*
 
4814
*  SYNOPSIS
 
4815
*     int parallel_assignment(sge_assignment_t *assignment) 
 
4816
*
 
4817
*  FUNCTION
 
4818
*     Returns if possible an assignment for a particular PE with a 
 
4819
*     fixed slot at a fixed time.
 
4820
*
 
4821
*  INPUTS
 
4822
*     sge_assignment_t *a - 
 
4823
*     category_use_t *use_category - has information on how to use the job category
 
4824
*
 
4825
*  RESULT
 
4826
*     dispatch_t -  0 ok got an assignment
 
4827
*                   1 no assignment at the specified time
 
4828
*                  -1 assignment will never be possible for all jobs of that category
 
4829
*                  -2 assignment will never be possible for that particular job
 
4830
*
 
4831
*  NOTES
 
4832
*     MT-NOTE: parallel_assignment() is not MT safe 
 
4833
*******************************************************************************/
 
4834
static dispatch_t
 
4835
parallel_assignment(sge_assignment_t *a, category_use_t *use_category, int *available_slots) 
 
4836
{
 
4837
   dispatch_t ret;
 
4838
   int pslots = a->slots;
 
4839
   int pslots_qend = 0;
 
4840
 
 
4841
#ifdef SGE_PQS_API
 
4842
   const char *qsort_args;
 
4843
#endif
 
4844
 
 
4845
   DENTER(TOP_LAYER, "parallel_assignment");
 
4846
 
 
4847
   if (a == NULL) {
 
4848
      DRETURN(DISPATCH_NEVER_CAT);
 
4849
   }
 
4850
 
 
4851
   if ((lGetUlong(a->job, JB_ar) == 0) &&  (ret = parallel_available_slots(a, &pslots, &pslots_qend)) != DISPATCH_OK) {
 
4852
      *available_slots = MIN(pslots, pslots_qend);
 
4853
      DRETURN(ret); 
 
4854
   }
 
4855
   if (a->slots > pslots) {
 
4856
      *available_slots = MIN(pslots, pslots_qend);
 
4857
      DRETURN((a->slots > pslots_qend)? DISPATCH_NEVER_CAT : DISPATCH_NOT_AT_TIME);
 
4858
   }
 
4859
 
 
4860
 
 
4861
   /* depends on a correct host order */
 
4862
   ret = parallel_tag_queues_suitable4job(a, use_category, available_slots);
 
4863
 
 
4864
   if (ret != DISPATCH_OK) {
 
4865
      DRETURN(ret);
 
4866
   }
 
4867
 
 
4868
 
 
4869
   /* must be understood in the context of changing queue sort orders */
 
4870
   sconf_set_last_dispatch_type(DISPATCH_TYPE_COMPREHENSIVE);
 
4871
 
 
4872
#ifdef SGE_PQS_API
 
4873
   /* if dynamic qsort function was supplied, call it */
 
4874
   if ((qsort_args=lGetString(a->pe, PE_qsort_args)) != NULL) {
 
4875
 
 
4876
      ret = sge_call_pe_qsort(a, qsort_args);
 
4877
      if (ret!=0) {
 
4878
         DRETURN(ret);
 
4879
      }
 
4880
   }
 
4881
#endif
 
4882
 
 
4883
   DRETURN(ret);
 
4884
}
 
4885
 
 
4886
 
 
4887
 
 
4888
/****** sched/select_queue/parallel_queue_slots() *************************
 
4889
*  NAME
 
4890
*     parallel_queue_slots() -- 
 
4891
*
 
4892
*  RESULT
 
4893
*     int - 0 ok got an assignment + set time for DISPATCH_TIME_NOW and 
 
4894
*             DISPATCH_TIME_QUEUE_END (only with fixed_slot equals true)
 
4895
*           1 no assignment at the specified time
 
4896
*          -1 assignment will never be possible for all jobs of that category
 
4897
******************************************************************************/
 
4898
static dispatch_t
 
4899
parallel_queue_slots(sge_assignment_t *a, lListElem *qep, int *slots, int *slots_qend, 
 
4900
                    bool allow_non_requestable) 
 
4901
{
 
4902
   lList *hard_requests = lGetList(a->job, JB_hard_resource_list);
 
4903
   lList *config_attr = lGetList(qep, QU_consumable_config_list);
 
4904
   lList *actual_attr = lGetList(qep, QU_resource_utilization);
 
4905
   const char *qname = lGetString(qep, QU_full_name);
 
4906
   int qslots = 0, qslots_qend = 0;
 
4907
   int lslots = INT_MAX, lslots_qend = INT_MAX;
 
4908
 
 
4909
   dispatch_t result = DISPATCH_NEVER_CAT;
 
4910
 
 
4911
   DENTER(TOP_LAYER, "parallel_queue_slots");
 
4912
 
 
4913
   if (a->pi)
 
4914
      a->pi->par_qstat++;
 
4915
 
 
4916
   if (sge_queue_match_static(qep, a->job, a->pe, a->ckpt, a->centry_list,
 
4917
                              a->acl_list, a->hgrp_list, a->ar_list) == DISPATCH_OK) {
 
4918
      lListElem *gdil;
 
4919
                                    
 
4920
      u_long32 ar_id = lGetUlong(a->job, JB_ar);
 
4921
 
 
4922
      if (ar_id != 0) {
 
4923
         lListElem *ar_queue;
 
4924
         lListElem *rep;
 
4925
         lList *ar_queue_config_attr;
 
4926
         lList *ar_queue_actual_attr;
 
4927
         lListElem *ar_ep = lGetElemUlong(a->ar_list, AR_id, ar_id);
 
4928
         lList *hard_resource_list = lGetList(a->job, JB_hard_resource_list);
 
4929
         dstring reason = DSTRING_INIT;
 
4930
 
 
4931
         clear_resource_tags(hard_resource_list, QUEUE_TAG); 
 
4932
 
 
4933
         ar_queue_config_attr = lGetList(qep, QU_consumable_config_list);
 
4934
         ar_queue_actual_attr = lGetList(qep, QU_resource_utilization);
 
4935
 
 
4936
         for_each(rep, hard_resource_list) {
 
4937
            const char *attrname = lGetString(rep, CE_name);
 
4938
            lListElem *cplx_el = lGetElemStr(a->centry_list, CE_name, attrname);
 
4939
 
 
4940
            if (lGetBool(cplx_el, CE_consumable)) {
 
4941
               continue;
 
4942
            }
 
4943
            sge_dstring_clear(&reason);
 
4944
            cplx_el = get_attribute(attrname, ar_queue_config_attr, ar_queue_actual_attr, NULL, a->centry_list, NULL,
 
4945
                     DOMINANT_LAYER_QUEUE, 0, &reason, false, DISPATCH_TIME_NOW, 0);
 
4946
            if (cplx_el != NULL) {
 
4947
               if (match_static_resource(1, rep, cplx_el, &reason, false, false, false) == DISPATCH_OK) {
 
4948
                  lSetUlong(rep, CE_tagged, PE_TAG); 
 
4949
               }
 
4950
               lFreeElem(&cplx_el);
 
4951
            }
 
4952
         }
 
4953
         sge_dstring_free(&reason);
 
4954
 
 
4955
         ar_queue = lGetSubStr(ar_ep, QU_full_name, qname, AR_reserved_queues);
 
4956
         ar_queue_config_attr = lGetList(ar_queue, QU_consumable_config_list);
 
4957
         ar_queue_actual_attr = lGetList(ar_queue, QU_resource_utilization);
 
4958
 
 
4959
         DPRINTF(("verifing AR queue\n"));
 
4960
         result = parallel_rc_slots_by_time(a, hard_requests, &qslots, &qslots_qend, 
 
4961
               ar_queue_config_attr, ar_queue_actual_attr, NULL, true, ar_queue, 
 
4962
               DOMINANT_LAYER_QUEUE, 0, QUEUE_TAG, false, lGetString(ar_queue, QU_full_name), false);
 
4963
      } else {
 
4964
         if (a->is_advance_reservation 
 
4965
            || (((a->pi)?a->pi->par_rqs++:0), result = parallel_rqs_slots_by_time(a, &lslots, &lslots_qend, 
 
4966
                 lGetHost(qep, QU_qhostname), lGetString(qep, QU_qname))) == DISPATCH_OK) {
 
4967
            DPRINTF(("verifing normal queue\n"));
 
4968
 
 
4969
            if (a->pi)
 
4970
               a->pi->par_qdyn++;
 
4971
 
 
4972
            result = parallel_rc_slots_by_time(a, hard_requests, &qslots, &qslots_qend, 
 
4973
                  config_attr, actual_attr, NULL, true, qep, 
 
4974
                  DOMINANT_LAYER_QUEUE, 0, QUEUE_TAG, false, lGetString(qep, QU_full_name), false);
 
4975
         }
 
4976
      }
 
4977
 
 
4978
      if ((gdil=lGetElemStr(a->gdil, JG_qname, lGetString(qep, QU_full_name))))
 
4979
         qslots -= lGetUlong(gdil, JG_slots);
 
4980
   }
 
4981
 
 
4982
 
 
4983
   *slots = MIN(qslots, lslots);
 
4984
   *slots_qend = MIN(qslots_qend, lslots_qend);
 
4985
 
 
4986
   if (result == DISPATCH_OK) {
 
4987
      DPRINTF(("\tparallel_queue_slots(%s) returns %d/%d\n", qname, qslots, qslots_qend));
 
4988
   } else {
 
4989
      DPRINTF(("\tparallel_queue_slots(%s) returns <error>\n", qname));
 
4990
   }
 
4991
 
 
4992
   DRETURN(result);
 
4993
}
 
4994
 
 
4995
/****** sched/select_queue/sequential_queue_time() *************************
 
4996
*  NAME
 
4997
*     sequential_queue_time() -- 
 
4998
*
 
4999
*  RESULT
 
5000
*      dispatch_t - 0 ok got an assignment + set time for DISPATCH_TIME_NOW and 
 
5001
*                     DISPATCH_TIME_QUEUE_END (only with fixed_slot equals true)
 
5002
*                   1 no assignment at the specified time
 
5003
*                  -1 assignment will never be possible for all jobs of that category
 
5004
******************************************************************************/
 
5005
static dispatch_t 
 
5006
sequential_queue_time(u_long32 *start, const sge_assignment_t *a,
 
5007
                                int *violations, lListElem *qep) 
 
5008
{
 
5009
   dstring reason; 
 
5010
   char reason_buf[1024];
 
5011
   dispatch_t result;
 
5012
   u_long32 tmp_time = *start;
 
5013
   lList *hard_requests = lGetList(a->job, JB_hard_resource_list);
 
5014
   lList *config_attr = lGetList(qep, QU_consumable_config_list);
 
5015
   lList *actual_attr = lGetList(qep, QU_resource_utilization);
 
5016
   const char *qname = lGetString(qep, QU_full_name);
 
5017
 
 
5018
   DENTER(TOP_LAYER, "sequential_queue_time");
 
5019
 
 
5020
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
5021
 
 
5022
   /* match the resources */
 
5023
   result = rc_time_by_slots(a, hard_requests, NULL, config_attr, actual_attr, 
 
5024
                            qep, false, &reason, 1, DOMINANT_LAYER_QUEUE, 
 
5025
                            0, QUEUE_TAG, &tmp_time, qname);
 
5026
 
 
5027
   if (result == DISPATCH_OK) {
 
5028
      if (violations != NULL) {
 
5029
         *violations = compute_soft_violations(a, qep, *violations, NULL, config_attr, actual_attr, 
 
5030
                                           DOMINANT_LAYER_QUEUE, 0, QUEUE_TAG);
 
5031
      }      
 
5032
   } else {
 
5033
      char buff[1024 + 1];
 
5034
      centry_list_append_to_string(hard_requests, buff, sizeof(buff) - 1);
 
5035
      if (*buff && (buff[strlen(buff) - 1] == '\n')) {
 
5036
         buff[strlen(buff) - 1] = 0;
 
5037
      }   
 
5038
      schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNINQUEUE_SSS, buff, qname, reason_buf);
 
5039
   }
 
5040
 
 
5041
   if (a->is_reservation && result == DISPATCH_OK) {
 
5042
      *start = tmp_time;
 
5043
      DPRINTF(("queue_time_by_slots(%s) returns earliest start time "sge_u32"\n", qname, *start));
 
5044
   } else if (result == DISPATCH_OK) {
 
5045
      DPRINTF(("queue_time_by_slots(%s) returns <at specified time>\n", qname));
 
5046
   } else {
 
5047
      DPRINTF(("queue_time_by_slots(%s) returns <later>\n", qname));
 
5048
   }
 
5049
 
 
5050
   DRETURN(result); 
 
5051
}
 
5052
 
 
5053
 
 
5054
 
 
5055
 
 
5056
/****** sge_select_queue/host_time_by_slots() ******************************
 
5057
*  NAME
 
5058
*     host_time_by_slots() -- Return time when host slots are available
 
5059
*
 
5060
*  SYNOPSIS
 
5061
*     int host_time_by_slots(int slots, u_long32 *start, u_long32 duration, 
 
5062
*     int *host_soft_violations, lListElem *job, lListElem *ja_task, lListElem 
 
5063
*     *hep, lList *centry_list, lList *acl_list) 
 
5064
*
 
5065
*  FUNCTION
 
5066
*     The time when the specified slot amount is available at the host 
 
5067
*     is determined. Behaviour depends on input/output parameter start
 
5068
*
 
5069
*     DISPATCH_TIME_NOW 
 
5070
*           0 an assignment is possible now
 
5071
*           1 no assignment now but later
 
5072
*          -1 assignment never possible for all jobs of the same category
 
5073
*          -2 assignment never possible for that particular job
 
5074
*
 
5075
*     <any other time>
 
5076
*           0 an assignment is possible at the specified time
 
5077
*           1 no assignment at specified time but later
 
5078
*          -1 assignment never possible for all jobs of the same category
 
5079
*          -2 assignment never possible for that particular job
 
5080
*
 
5081
*     DISPATCH_TIME_QUEUE_END
 
5082
*           0 an assignment is possible and the start time is returned
 
5083
*          -1 assignment never possible for all jobs of the same category
 
5084
*          -2 assignment never possible for that particular job
 
5085
*
 
5086
*  INPUTS
 
5087
*     int slots                 - ??? 
 
5088
*     u_long32 *start           - ??? 
 
5089
*     u_long32 duration         - ??? 
 
5090
*     int *host_soft_violations - ??? 
 
5091
*     lListElem *job            - ??? 
 
5092
*     lListElem *ja_task        - ??? 
 
5093
*     lListElem *hep            - ??? 
 
5094
*     lList *centry_list        - ??? 
 
5095
*     lList *acl_list           - ??? 
 
5096
*
 
5097
*  RESULT
 
5098
*******************************************************************************/
 
5099
static dispatch_t
 
5100
sequential_host_time(u_long32 *start, const sge_assignment_t *a,
 
5101
                              int *violations, lListElem *hep) 
 
5102
{
 
5103
   lList *hard_requests = lGetList(a->job, JB_hard_resource_list);
 
5104
   lList *load_attr = lGetList(hep, EH_load_list); 
 
5105
   lList *config_attr = lGetList(hep, EH_consumable_config_list);
 
5106
   lList *actual_attr = lGetList(hep, EH_resource_utilization);
 
5107
   double lc_factor = 0;
 
5108
   u_long32 ulc_factor;
 
5109
   dispatch_t result;
 
5110
   u_long32 tmp_time = *start;
 
5111
   const char *eh_name = lGetHost(hep, EH_name);
 
5112
   dstring reason; char reason_buf[1024];
 
5113
  
 
5114
   DENTER(TOP_LAYER, "sequential_host_time");
 
5115
 
 
5116
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
5117
 
 
5118
   clear_resource_tags(hard_requests, HOST_TAG);
 
5119
 
 
5120
   /* cause load be raised artificially to reflect load correction when
 
5121
      checking job requests */
 
5122
   if (lGetPosViaElem(hep, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
5123
      if ((ulc_factor=lGetUlong(hep, EH_load_correction_factor)))
 
5124
         lc_factor = ((double)ulc_factor)/100;
 
5125
   }
 
5126
 
 
5127
   result = rc_time_by_slots(a, hard_requests, load_attr, 
 
5128
         config_attr, actual_attr, NULL, false, 
 
5129
         &reason, 1, DOMINANT_LAYER_HOST, 
 
5130
         lc_factor, HOST_TAG, &tmp_time, eh_name);
 
5131
 
 
5132
   if (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR) {
 
5133
      if (violations != NULL) {
 
5134
         *violations = compute_soft_violations(a, NULL, *violations, load_attr, config_attr, 
 
5135
                                           actual_attr, DOMINANT_LAYER_HOST, 0, HOST_TAG);
 
5136
      }      
 
5137
   } else {
 
5138
      char buff[1024 + 1];
 
5139
      centry_list_append_to_string(hard_requests, buff, sizeof(buff) - 1);
 
5140
      if (*buff && (buff[strlen(buff) - 1] == '\n'))
 
5141
         buff[strlen(buff) - 1] = 0;
 
5142
      schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNATHOST_SSS, buff, eh_name, reason_buf);
 
5143
   }
 
5144
 
 
5145
   if (a->is_reservation && (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR)) {
 
5146
      *start = tmp_time;
 
5147
      DPRINTF(("host_time_by_slots(%s) returns earliest start time "sge_u32"\n", eh_name, *start));
 
5148
   } else if (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR) {
 
5149
      DPRINTF(("host_time_by_slots(%s) returns <at specified time>\n", eh_name));
 
5150
   } else {
 
5151
      DPRINTF(("host_time_by_slots(%s) returns <later>\n", eh_name));
 
5152
   }
 
5153
 
 
5154
   DRETURN(result); 
 
5155
}
 
5156
 
 
5157
/****** sched/select_queue/sequential_global_time() ***************************
 
5158
*  NAME
 
5159
*     sequential_global_time() -- 
 
5160
*
 
5161
*  RESULT
 
5162
*     int - 0 ok got an assignment + set time for DISPATCH_TIME_QUEUE_END
 
5163
*           1 no assignment at the specified time
 
5164
*          -1 assignment will never be possible for all jobs of that category
 
5165
******************************************************************************/
 
5166
static dispatch_t
 
5167
sequential_global_time(u_long32 *start, const sge_assignment_t *a, int *violations)
 
5168
{
 
5169
   dstring reason; char reason_buf[1024];
 
5170
   dispatch_t result = DISPATCH_NEVER_CAT;
 
5171
   u_long32 tmp_time = *start; 
 
5172
   lList *hard_request = lGetList(a->job, JB_hard_resource_list);
 
5173
   lList *load_attr = lGetList(a->gep, EH_load_list); 
 
5174
   lList *config_attr = lGetList(a->gep, EH_consumable_config_list);
 
5175
   lList *actual_attr = lGetList(a->gep, EH_resource_utilization);
 
5176
   double lc_factor=0.0;
 
5177
   u_long32 ulc_factor;
 
5178
 
 
5179
   DENTER(TOP_LAYER, "sequential_global_time");
 
5180
 
 
5181
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
5182
 
 
5183
   clear_resource_tags(hard_request, GLOBAL_TAG);
 
5184
 
 
5185
   /* check if job has access to any hosts globally */
 
5186
   if ((result=sge_host_match_static(a->job, NULL, a->gep, a->centry_list, 
 
5187
            a->acl_list)) != 0) {
 
5188
      DRETURN(result);
 
5189
   }
 
5190
   
 
5191
   /* cause global load be raised artificially to reflect load correction when
 
5192
      checking job requests */
 
5193
   if (lGetPosViaElem(a->gep, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
5194
      if ((ulc_factor=lGetUlong(a->gep, EH_load_correction_factor)))
 
5195
         lc_factor = ((double)ulc_factor)/100;
 
5196
   }
 
5197
 
 
5198
   result = rc_time_by_slots(a, hard_request, load_attr, config_attr, actual_attr, NULL, false, &reason, 
 
5199
                             1, DOMINANT_LAYER_GLOBAL, lc_factor, GLOBAL_TAG, &tmp_time, SGE_GLOBAL_NAME);
 
5200
 
 
5201
   if ((result == DISPATCH_OK) || (result == DISPATCH_MISSING_ATTR)) {
 
5202
      if (violations != NULL) {
 
5203
         *violations = compute_soft_violations(a, NULL, *violations, load_attr, config_attr, 
 
5204
                                           actual_attr, DOMINANT_LAYER_GLOBAL, 0, GLOBAL_TAG);
 
5205
      }      
 
5206
   } else {
 
5207
      char buff[1024 + 1];
 
5208
      centry_list_append_to_string(hard_request, buff, sizeof(buff) - 1);
 
5209
      if (*buff && (buff[strlen(buff) - 1] == '\n')) {
 
5210
         buff[strlen(buff) - 1] = 0;
 
5211
      }   
 
5212
      schedd_mes_add (a->job_id, SCHEDD_INFO_CANNOTRUNGLOBALLY_SS, buff, reason_buf);
 
5213
   }
 
5214
 
 
5215
   if (a->is_reservation && (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR)) {
 
5216
      *start = tmp_time;
 
5217
      DPRINTF(("global_time_by_slots() returns earliest start time "sge_u32"\n", *start));
 
5218
   } 
 
5219
   else if (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR) {
 
5220
      DPRINTF(("global_time_by_slots() returns <at specified time>\n"));
 
5221
   } 
 
5222
   else {
 
5223
      DPRINTF(("global_time_by_slots() returns <later>\n"));
 
5224
   }
 
5225
 
 
5226
   DRETURN(result);
 
5227
}
 
5228
 
 
5229
/****** sched/select_queue/parallel_global_slots() ***************************
 
5230
*  NAME
 
5231
*     parallel_global_slots() -- 
 
5232
*
 
5233
*  RESULT
 
5234
*     dispatch_t -  0 ok got an assignment + set time for DISPATCH_TIME_QUEUE_END
 
5235
*                   1 no assignment at the specified time
 
5236
*                  -1 assignment will never be possible for all jobs of that category
 
5237
******************************************************************************/
 
5238
static dispatch_t 
 
5239
parallel_global_slots(const sge_assignment_t *a, int *slots, int *slots_qend)
 
5240
{
 
5241
   dispatch_t result = DISPATCH_NEVER_CAT;
 
5242
   lList *hard_request = lGetList(a->job, JB_hard_resource_list);
 
5243
   lList *load_attr = lGetList(a->gep, EH_load_list); 
 
5244
   lList *config_attr = lGetList(a->gep, EH_consumable_config_list);
 
5245
   lList *actual_attr = lGetList(a->gep, EH_resource_utilization);
 
5246
   double lc_factor=0.0;
 
5247
   int gslots = 0, gslots_qend = 0;
 
5248
 
 
5249
   DENTER(TOP_LAYER, "parallel_global_slots");
 
5250
 
 
5251
   clear_resource_tags(hard_request, GLOBAL_TAG);
 
5252
 
 
5253
   /* check if job has access to any hosts globally */
 
5254
   if (sge_host_match_static(a->job, NULL, a->gep, a->centry_list, a->acl_list) == DISPATCH_OK) {
 
5255
      /* cause global load be raised artificially to reflect load correction when
 
5256
         checking job requests */
 
5257
 
 
5258
      if (lGetPosViaElem(a->gep, EH_load_correction_factor, SGE_NO_ABORT) >= 0) {
 
5259
         u_long32 ulc_factor;
 
5260
         if ((ulc_factor=lGetUlong(a->gep, EH_load_correction_factor))) {
 
5261
            lc_factor = ((double)ulc_factor)/100;
 
5262
         }
 
5263
      }
 
5264
 
 
5265
      result = parallel_rc_slots_by_time(a, hard_request, &gslots, 
 
5266
                                &gslots_qend, config_attr, actual_attr, load_attr,  
 
5267
                                false, NULL, DOMINANT_LAYER_GLOBAL, lc_factor, GLOBAL_TAG, false, SGE_GLOBAL_NAME, false);
 
5268
   }
 
5269
 
 
5270
   *slots      = gslots;
 
5271
   *slots_qend = gslots_qend;
 
5272
 
 
5273
   if (result == DISPATCH_OK) {
 
5274
      DPRINTF(("\tparallel_global_slots() returns %d/%d\n", gslots, gslots_qend));
 
5275
   } 
 
5276
   else {
 
5277
      DPRINTF(("\tparallel_global_slots() returns <error>\n"));
 
5278
   }
 
5279
 
 
5280
   DRETURN(result);
 
5281
}
 
5282
 
 
5283
/****** sge_select_queue/parallel_available_slots() **********************************
 
5284
*  NAME
 
5285
*     parallel_available_slots() -- Check if number of PE slots is available 
 
5286
*
 
5287
*  SYNOPSIS
 
5288
*
 
5289
*  FUNCTION
 
5290
*
 
5291
*  INPUTS
 
5292
*
 
5293
*  RESULT
 
5294
*     dispatch_t - 0 ok got an assignment
 
5295
*                  1 no assignment at the specified time
 
5296
*                 -1 assignment will never be possible for all jobs of that category
 
5297
*
 
5298
*  NOTES
 
5299
*     MT-NOTE: parallel_available_slots() is not MT safe 
 
5300
*******************************************************************************/
 
5301
static dispatch_t 
 
5302
parallel_available_slots(const sge_assignment_t *a, int *slots, int *slots_qend) 
 
5303
{
 
5304
   dstring reason; 
 
5305
   char reason_buf[1024];
 
5306
   dispatch_t result;
 
5307
   int total = lGetUlong(a->pe, PE_slots);
 
5308
   int pslots=0; 
 
5309
   int pslots_qend=0;
 
5310
   static lListElem *implicit_slots_request = NULL;
 
5311
   static lList *implicit_total_list = NULL;
 
5312
   lListElem *tep = NULL;
 
5313
   char strbuf[100];
 
5314
   dstring slots_as_str;
 
5315
 
 
5316
   DENTER(TOP_LAYER, "parallel_available_slots");
 
5317
 
 
5318
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
5319
   
 
5320
   if ((result=pe_match_static(a->job, a->pe, a->acl_list)) != DISPATCH_OK) {
 
5321
      DRETURN(result);
 
5322
   }
 
5323
 
 
5324
   if (!implicit_slots_request) {
 
5325
      implicit_slots_request = lCreateElem(CE_Type);
 
5326
      lSetString(implicit_slots_request, CE_name, SGE_ATTR_SLOTS);
 
5327
      lSetString(implicit_slots_request, CE_stringval, "1");
 
5328
      lSetDouble(implicit_slots_request, CE_doubleval, 1);
 
5329
   }
 
5330
 
 
5331
   /* PE slots should be stored in a PE_consumable_config_list ... */
 
5332
   if (!implicit_total_list) {
 
5333
      tep = lAddElemStr(&implicit_total_list, CE_name, SGE_ATTR_SLOTS, CE_Type);
 
5334
   }
 
5335
   
 
5336
   if (!tep && !(tep = lGetElemStr(implicit_total_list, CE_name, SGE_ATTR_SLOTS))) {
 
5337
      DRETURN(DISPATCH_NEVER_CAT);
 
5338
   }
 
5339
 
 
5340
   total = lGetUlong(a->pe, PE_slots);
 
5341
   lSetDouble(tep, CE_doubleval, total);
 
5342
   sge_dstring_init(&slots_as_str, strbuf, sizeof(strbuf));
 
5343
   sge_dstring_sprintf(&slots_as_str, "%d", total);
 
5344
   lSetString(tep, CE_stringval, strbuf);
 
5345
 
 
5346
   if (ri_slots_by_time(a, &pslots, &pslots_qend, 
 
5347
         lGetList(a->pe, PE_resource_utilization), implicit_slots_request, 
 
5348
         NULL, implicit_total_list, NULL, 0, 0, &reason, true, true, a->pe_name)) {
 
5349
      DRETURN(DISPATCH_NEVER_CAT);
 
5350
   }
 
5351
 
 
5352
   if (slots) {
 
5353
      *slots = pslots;
 
5354
   }
 
5355
 
 
5356
   if (slots_qend) {
 
5357
      *slots_qend = pslots_qend;
 
5358
   }   
 
5359
 
 
5360
   DPRINTF(("\tparallel_available_slots(%s) returns %d/%d\n", a->pe_name,
 
5361
         pslots, pslots_qend));
 
5362
 
 
5363
   DRETURN(DISPATCH_OK);
 
5364
}
 
5365
 
 
5366
 
 
5367
/* ----------------------------------------
 
5368
 
 
5369
   sge_get_double_qattr() 
 
5370
 
 
5371
   writes actual value of the queue attriute into *uvalp 
 
5372
 
 
5373
   returns:
 
5374
      0 ok, value in *uvalp is valid
 
5375
      -1 the queue has no such attribute
 
5376
      -2 type error: cant compute uval from actual string value 
 
5377
 
 
5378
*/      
 
5379
int 
 
5380
sge_get_double_qattr(double *dvalp, char *attrname, lListElem *q, 
 
5381
                     const lList *exechost_list, const lList *centry_list, 
 
5382
                     bool *has_value_from_object) 
 
5383
{
 
5384
   int ret = -1;
 
5385
   lListElem *ep;
 
5386
   u_long32 type;
 
5387
   double tmp_dval;
 
5388
   char dom_str[4];
 
5389
   lListElem *global = NULL;
 
5390
   lListElem *host = NULL;
 
5391
 
 
5392
   DENTER(TOP_LAYER, "sge_get_double_qattr");
 
5393
 
 
5394
   global = host_list_locate(exechost_list, SGE_GLOBAL_NAME); 
 
5395
   host = host_list_locate(exechost_list, lGetHost(q, QU_qhostname));
 
5396
 
 
5397
   /* find matching */
 
5398
   *has_value_from_object = false;
 
5399
   if (( ep = get_attribute_by_name(global, host, q, attrname, centry_list, DISPATCH_TIME_NOW, 0)) &&
 
5400
         ((type=lGetUlong(ep, CE_valtype)) != TYPE_STR) && 
 
5401
         (type != TYPE_CSTR) && (type != TYPE_RESTR) && (type != TYPE_HOST) ) {
 
5402
         
 
5403
         if ((lGetUlong(ep, CE_pj_dominant)&DOMINANT_TYPE_MASK)!=DOMINANT_TYPE_VALUE ) {
 
5404
            parse_ulong_val(&tmp_dval, NULL, type, lGetString(ep, CE_pj_stringval), NULL, 0);
 
5405
            monitor_dominance(dom_str, lGetUlong(ep, CE_pj_dominant));
 
5406
            *has_value_from_object = true;
 
5407
         } else {
 
5408
            parse_ulong_val(&tmp_dval, NULL, type, lGetString(ep, CE_stringval), NULL, 0); 
 
5409
            monitor_dominance(dom_str, lGetUlong(ep, CE_dominant));
 
5410
            *has_value_from_object = ((lGetUlong(ep, CE_dominant) & DOMINANT_TYPE_MASK) == DOMINANT_TYPE_VALUE) ? false : true;
 
5411
         }
 
5412
      ret = 0;
 
5413
      if (dvalp)
 
5414
         *dvalp = tmp_dval;
 
5415
      DPRINTF(("resource %s: %f\n", dom_str, tmp_dval));
 
5416
   }
 
5417
 
 
5418
   /* free */
 
5419
   lFreeElem(&ep);
 
5420
 
 
5421
   DRETURN(ret);
 
5422
}
 
5423
 
 
5424
 
 
5425
/* ----------------------------------------
 
5426
 
 
5427
   sge_get_string_qattr() 
 
5428
 
 
5429
   writes string value into dst
 
5430
 
 
5431
   returns:
 
5432
      -1    if the queue has no such attribute
 
5433
      0 
 
5434
*/      
 
5435
int sge_get_string_qattr(
 
5436
char *dst,
 
5437
int dst_len,
 
5438
char *attrname,
 
5439
lListElem *q,
 
5440
const lList *exechost_list,
 
5441
const lList *centry_list 
 
5442
) {
 
5443
   lListElem *ep;
 
5444
   lListElem *global = NULL;
 
5445
   lListElem *host = NULL;
 
5446
   int ret = 0;
 
5447
 
 
5448
   DENTER(TOP_LAYER, "sge_get_string_qattr");
 
5449
 
 
5450
   global = host_list_locate(exechost_list, SGE_GLOBAL_NAME); 
 
5451
   host = host_list_locate(exechost_list, lGetHost(q, QU_qhostname));
 
5452
 
 
5453
   ep = get_attribute_by_name(global, host, q, attrname, centry_list, DISPATCH_TIME_NOW, 0);
 
5454
 
 
5455
   /* first copy ... */
 
5456
   if (ep && dst)
 
5457
      sge_strlcpy(dst, lGetString(ep, CE_stringval), dst_len);
 
5458
 
 
5459
   if(ep){
 
5460
      lFreeElem(&ep);
 
5461
      ret = 0;
 
5462
   }
 
5463
   else
 
5464
      ret = -1;
 
5465
   /* ... and then free */
 
5466
 
 
5467
   DRETURN(ret); 
 
5468
}
 
5469
 
 
5470
/****** sge_select_queue/ri_time_by_slots() ******************************************
 
5471
*  NAME
 
5472
*     ri_time_by_slots() -- Determine availability time through slot number
 
5473
*
 
5474
*  SYNOPSIS
 
5475
*     int ri_time_by_slots(lListElem *rep, lList *load_attr, lList 
 
5476
*     *config_attr, lList *actual_attr, lList *centry_list, lListElem *queue, 
 
5477
*     char *reason, int reason_size, bool allow_non_requestable, int slots, 
 
5478
*     u_long32 layer, double lc_factor) 
 
5479
*
 
5480
*  FUNCTION
 
5481
*     Checks for one level, if one request is fulfilled or not. 
 
5482
 
5483
*     With reservation scheduling the earliest start time due to 
 
5484
*     availability of the resource instance is determined by ensuring 
 
5485
*     non-consumable resource requests are fulfilled or by finding the 
 
5486
*     earliest time utilization of a consumable resource is below the
 
5487
*     threshold required for the request.
 
5488
*
 
5489
*  INPUTS
 
5490
*     sge_assignment_t *a       - assignment object that holds job specific scheduling relevant data
 
5491
*     lListElem *rep            - requested attribute 
 
5492
*     lList *load_attr          - list of load attributes or null on queue level 
 
5493
*     lList *config_attr        - list of user defined attributes (CE_Type)
 
5494
*     lList *actual_attr        - usage of user consumables (RUE_Type)
 
5495
*i    lListElem *queue          - the current queue, or null on host level 
 
5496
*     dstring *reason           - target for error message 
 
5497
*     bool allow_non_requestable - allow none requestable attributes? 
 
5498
*     int slots                 - the number of slotes the job is looking for? 
 
5499
*     u_long32 layer            - the current layer 
 
5500
*     double lc_factor          - load correction factor 
 
5501
*     u_long32 *start_time      - in/out argument for start time  
 
5502
*     const char *object_name   - name of the object used for monitoring purposes
 
5503
*
 
5504
*  RESULT
 
5505
*     dispatch_t - 
 
5506
*
 
5507
*******************************************************************************/
 
5508
dispatch_t
 
5509
ri_time_by_slots(const sge_assignment_t *a, lListElem *rep, lList *load_attr, lList *config_attr, lList *actual_attr, 
 
5510
                 lListElem *queue, dstring *reason, bool allow_non_requestable, 
 
5511
                 int slots, u_long32 layer, double lc_factor, u_long32 *start_time, const char *object_name) 
 
5512
{
 
5513
   lListElem *cplx_el=NULL;
 
5514
   const char *attrname; 
 
5515
   dispatch_t ret = DISPATCH_OK;
 
5516
   lListElem *actual_el;
 
5517
   u_long32 ready_time;
 
5518
   double util, total, request = 0;
 
5519
   lListElem *capacitiy_el;
 
5520
   bool schedule_based = (a->is_advance_reservation || a->is_schedule_based) ? true : false;
 
5521
   u_long32 now = sconf_get_now();
 
5522
   int utilized = 0;
 
5523
 
 
5524
   DENTER(TOP_LAYER, "ri_time_by_slots");
 
5525
 
 
5526
   attrname = lGetString(rep, CE_name);
 
5527
   actual_el = lGetElemStr(actual_attr, RUE_name, attrname);
 
5528
   ready_time = *start_time;
 
5529
 
 
5530
   /*
 
5531
    * Consumables are treated futher below in schedule based mode 
 
5532
    * thus we always assume zero consumable utilization here 
 
5533
    */ 
 
5534
 
 
5535
   if (!(cplx_el = get_attribute(attrname, config_attr, actual_attr, load_attr, a->centry_list, queue, layer, 
 
5536
                        lc_factor, reason, schedule_based, DISPATCH_TIME_NOW, 0))) {
 
5537
      DRETURN(DISPATCH_MISSING_ATTR);
 
5538
   }
 
5539
 
 
5540
   ret = match_static_resource(slots, rep, cplx_el, reason, false, false, allow_non_requestable);
 
5541
   if (actual_el != NULL) {
 
5542
      utilized = lGetNumberOfElem(lGetList(actual_el, RUE_utilized));
 
5543
   } 
 
5544
 
 
5545
   if (ret != DISPATCH_OK || (!schedule_based && utilized == 0)) {
 
5546
      lFreeElem(&cplx_el);
 
5547
      DRETURN(ret);
 
5548
   }
 
5549
 
 
5550
   DPRINTF(("ri_time_by_slots(%s) consumable = %s\n", 
 
5551
         attrname, (lGetBool(cplx_el, CE_consumable)?"true":"false")));
 
5552
 
 
5553
   if (!lGetBool(cplx_el, CE_consumable)) {
 
5554
      if (ready_time == DISPATCH_TIME_QUEUE_END) {
 
5555
         *start_time = now;
 
5556
      }   
 
5557
      DPRINTF(("%s: ri_time_by_slots(%s) <is no consumable>\n", object_name, attrname));
 
5558
      lFreeElem(&cplx_el);
 
5559
      DRETURN(DISPATCH_OK); /* already checked */
 
5560
   }
 
5561
      
 
5562
   /* we're done if there is no consumable capacity */
 
5563
   if (!(capacitiy_el = lGetElemStr(config_attr, CE_name, attrname))) {
 
5564
      DPRINTF(("%s: ri_time_by_slots(%s) <does not exist>\n", object_name, attrname));
 
5565
      lFreeElem(&cplx_el);
 
5566
      DRETURN(DISPATCH_MISSING_ATTR); /* does not exist */
 
5567
   }
 
5568
      
 
5569
   /* determine 'total' and 'request' values */
 
5570
   total = lGetDouble(capacitiy_el, CE_doubleval);
 
5571
 
 
5572
   if (!parse_ulong_val(&request, NULL, lGetUlong(cplx_el, CE_valtype), 
 
5573
      lGetString(rep, CE_stringval), NULL, 0)) {
 
5574
      sge_dstring_append(reason, "wrong type");
 
5575
      lFreeElem(&cplx_el);
 
5576
      DRETURN(DISPATCH_NEVER_CAT);
 
5577
   }
 
5578
   lFreeElem(&cplx_el);
 
5579
 
 
5580
   if (ready_time == DISPATCH_TIME_QUEUE_END) {
 
5581
      double threshold = total - request * slots;
 
5582
 
 
5583
      /* verify there are enough resources in principle */
 
5584
      if (threshold < 0) {
 
5585
         ret = DISPATCH_NEVER_CAT;
 
5586
      } else {
 
5587
         /* seek for the time near queue end where resources are sufficient */
 
5588
         u_long32 when = utilization_below(actual_el, threshold, object_name);
 
5589
         if (when == 0) {
 
5590
            /* may happen only if scheduler code is run outside scheduler with 
 
5591
               DISPATCH_TIME_QUEUE_END time spec */
 
5592
            *start_time = now;
 
5593
         } 
 
5594
         else {
 
5595
            *start_time = when;
 
5596
         }   
 
5597
         ret = DISPATCH_OK;
 
5598
 
 
5599
         DPRINTF(("\t\t%s: time_by_slots: %d of %s=%f can be served %s\n", 
 
5600
               object_name, slots, attrname, request,
 
5601
                  ret == DISPATCH_OK ? "at time" : "never"));
 
5602
 
 
5603
      }
 
5604
      DRETURN(ret);
 
5605
   } 
 
5606
 
 
5607
   /* here we handle DISPATCH_TIME_NOW + any other time */
 
5608
   if (*start_time == DISPATCH_TIME_NOW) {
 
5609
      ready_time = now;
 
5610
   }   
 
5611
   else {
 
5612
      ready_time = *start_time;
 
5613
   }   
 
5614
 
 
5615
   util = utilization_max(actual_el, ready_time, a->duration);
 
5616
 
 
5617
   DPRINTF(("\t\t%s: time_by_slots: %s total = %f util = %f from "sge_U32CFormat" plus "sge_U32CFormat" seconds\n", 
 
5618
            object_name, attrname, total, util, ready_time, a->duration));
 
5619
 
 
5620
   /* ensure resource is sufficient from now until finish */
 
5621
   if (request * slots > total - util) {
 
5622
      char dom_str[5];
 
5623
      dstring availability; char availability_text[2048];
 
5624
 
 
5625
      sge_dstring_init(&availability, availability_text, sizeof(availability_text));
 
5626
      
 
5627
      /* we can't assign right now - maybe later ? */  
 
5628
      if (request * slots > total ) {
 
5629
         DPRINTF(("\t\t%s: time_by_slots: %s %f > %f (never)\n", object_name, attrname,
 
5630
            request * slots, total));
 
5631
         ret = DISPATCH_NEVER_CAT; /* surely not */
 
5632
      } 
 
5633
      else if (request * slots > total - utilization_queue_end(actual_el)) {
 
5634
         DPRINTF(("\t\t%s: time_by_slots: %s %f <= %f (but booked out!!)\n", object_name, attrname,
 
5635
            request * slots, total));
 
5636
         ret = DISPATCH_NEVER_CAT; /* booked out until infinity */
 
5637
      } 
 
5638
      else {
 
5639
         DPRINTF(("\t\t%s: time_by_slots: %s %f > %f (later)\n", object_name, attrname, 
 
5640
            request * slots, total - util));
 
5641
         ret = DISPATCH_NOT_AT_TIME;
 
5642
      }
 
5643
 
 
5644
      monitor_dominance(dom_str, DOMINANT_TYPE_CONSUMABLE | layer);
 
5645
      sge_dstring_sprintf(&availability, "%s:%s=%f", dom_str, attrname, total - util);
 
5646
      sge_dstring_append(reason, MSG_SCHEDD_ITOFFERSONLY);
 
5647
      sge_dstring_append(reason, availability_text);
 
5648
 
 
5649
      if ((a->duration != DISPATCH_TIME_NOW) &&
 
5650
          (request * slots <= total - utilization_max(actual_el, ready_time, DISPATCH_TIME_NOW))) {
 
5651
         sge_dstring_append(reason, MSG_SCHEDD_DUETORR);
 
5652
      }
 
5653
   } 
 
5654
   else {
 
5655
      ret = DISPATCH_OK;
 
5656
   }
 
5657
 
 
5658
   DPRINTF(("\t\t%s: time_by_slots: %d of %s=%f can be served %s\n", 
 
5659
         object_name, slots, attrname, request, 
 
5660
            ret == DISPATCH_OK ? "at time" : ((ret == DISPATCH_NOT_AT_TIME)? "later":"never")));
 
5661
 
 
5662
   DRETURN(ret);                                                       
 
5663
}
 
5664
 
 
5665
/****** sge_select_queue/ri_slots_by_time() ************************************
 
5666
*  NAME
 
5667
*     ri_slots_by_time() -- Determine number of slots avail. within time frame
 
5668
*
 
5669
*  SYNOPSIS
 
5670
*     static dispatch_t ri_slots_by_time(const sge_assignment_t *a, int *slots, 
 
5671
*     int *slots_qend, lList *rue_list, lListElem *request, lList *load_attr, 
 
5672
*     lList *total_list, lListElem *queue, u_long32 layer, double lc_factor, 
 
5673
*     dstring *reason, bool allow_non_requestable, bool no_centry, const char 
 
5674
*     *object_name) 
 
5675
*
 
5676
*  FUNCTION
 
5677
*     The number of slots available with a resource can be zero for static
 
5678
*     resources or is determined based on maximum utilization within the
 
5679
*     specific time frame, the total amount of the resource and the per
 
5680
*     task request of the parallel job (ri_slots_by_time())
 
5681
*
 
5682
*  INPUTS
 
5683
*     const sge_assignment_t *a  - ??? 
 
5684
*     int *slots                 - Returns maximum slots that can be served 
 
5685
*                                  within the specified time frame.
 
5686
*     int *slots_qend            - Returns the maximum possible number of slots
 
5687
*     lList *rue_list            - Resource utilization (RUE_Type)
 
5688
*     lListElem *request         - Job request (CE_Type)
 
5689
*     lList *load_attr           - Load information for the resource
 
5690
*     lList *total_list          - Total resource amount (CE_Type)
 
5691
*     lListElem *queue           - Queue instance (QU_Type) for queue-based resources
 
5692
*     u_long32 layer             - DOMINANT_LAYER_{GLOBAL|HOST|QUEUE}
 
5693
*     double lc_factor           - load correction factor
 
5694
*     dstring *reason            - diagnosis information if no rsrc available
 
5695
*     bool allow_non_requestable - ??? 
 
5696
*     bool no_centry             - ??? 
 
5697
*     const char *object_name    - ??? 
 
5698
*
 
5699
*  RESULT
 
5700
*     static dispatch_t - 
 
5701
*
 
5702
*  NOTES
 
5703
*     MT-NOTE: ri_slots_by_time() is not MT safe 
 
5704
*******************************************************************************/
 
5705
static dispatch_t
 
5706
ri_slots_by_time(const sge_assignment_t *a, int *slots, int *slots_qend, 
 
5707
   lList *rue_list, lListElem *request, lList *load_attr, lList *total_list, 
 
5708
   lListElem *queue, u_long32 layer, double lc_factor, dstring *reason, 
 
5709
   bool allow_non_requestable, bool no_centry, const char *object_name)
 
5710
{
 
5711
   const char *name;
 
5712
   lListElem *cplx_el, *uep, *tep = NULL;
 
5713
   u_long32 start = a->start;
 
5714
   bool schedule_based = (a->is_advance_reservation || a->is_schedule_based) ? true : false;
 
5715
   int utilized = 0;
 
5716
 
 
5717
   dispatch_t ret;
 
5718
   double used, total, request_val;
 
5719
 
 
5720
   DENTER(TOP_LAYER, "ri_slots_by_time");
 
5721
   
 
5722
   /* always assume zero consumable utilization in schedule based mode */
 
5723
 
 
5724
   name = lGetString(request, CE_name);
 
5725
   uep = lGetElemStr(rue_list, RUE_name, name);
 
5726
 
 
5727
   DPRINTF(("\t\t%s: ri_slots_by_time(%s)\n", object_name, name));
 
5728
 
 
5729
   if (!no_centry) {
 
5730
      if (!(cplx_el = get_attribute(name, total_list, rue_list, load_attr, a->centry_list, queue, layer, 
 
5731
                           lc_factor, reason, schedule_based, DISPATCH_TIME_NOW, 0))) {
 
5732
         DRETURN(DISPATCH_MISSING_ATTR); /* does not exist */
 
5733
      }
 
5734
 
 
5735
      ret = match_static_resource(1, request, cplx_el, reason, false, false, allow_non_requestable);
 
5736
      if (ret != DISPATCH_OK) {
 
5737
         lFreeElem(&cplx_el);
 
5738
         DRETURN(ret);
 
5739
      }
 
5740
 
 
5741
      if (ret == DISPATCH_OK && !lGetBool(cplx_el, CE_consumable)) {
 
5742
         lFreeElem(&cplx_el);
 
5743
         *slots      = INT_MAX;
 
5744
         *slots_qend = INT_MAX;
 
5745
         DRETURN(DISPATCH_OK); /* no limitations */
 
5746
      }
 
5747
 
 
5748
      /* we're done if there is no consumable capacity */
 
5749
      if (!(tep=lGetElemStr(total_list, CE_name, name))) {
 
5750
         lFreeElem(&cplx_el);
 
5751
         *slots      = INT_MAX;
 
5752
         *slots_qend = INT_MAX;
 
5753
         DRETURN(DISPATCH_OK);
 
5754
      }
 
5755
 
 
5756
      lFreeElem(&cplx_el);
 
5757
   }
 
5758
 
 
5759
   if (!tep && !(tep=lGetElemStr(total_list, CE_name, name))) {
 
5760
      DRETURN(DISPATCH_NEVER_CAT);
 
5761
   }
 
5762
   total = lGetDouble(tep, CE_doubleval);
 
5763
 
 
5764
   if (uep != NULL) {
 
5765
      utilized = lGetNumberOfElem(lGetList(uep, RUE_utilized));
 
5766
   } 
 
5767
 
 
5768
   if (!a->is_advance_reservation && sconf_get_qs_state() == QS_STATE_EMPTY) {
 
5769
      DPRINTF(("QS_STATE is empty, skipping extensive checks!\n"));
 
5770
      used = 0;
 
5771
   } else if ((schedule_based || utilized != 0)) {
 
5772
      if (!a->is_reservation) {
 
5773
         start = sconf_get_now();
 
5774
      }   
 
5775
      used = utilization_max(uep, start, a->duration);
 
5776
      DPRINTF(("\t\t%s: ri_slots_by_time: utilization_max("sge_u32", "sge_u32") returns %f\n", 
 
5777
            object_name, start, a->duration, used));
 
5778
   } else {
 
5779
      used = lGetDouble(lGetElemStr(rue_list, RUE_name, name), RUE_utilized_now);
 
5780
   }
 
5781
 
 
5782
   request_val = lGetDouble(request, CE_doubleval);
 
5783
 
 
5784
   if ((request_val != 0) && (total < DBL_MAX)) {
 
5785
      *slots      = (int)((total - used) / request_val);
 
5786
      if (uep)
 
5787
         *slots_qend = (int)((total - utilization_queue_end(uep)) / request_val);
 
5788
      else
 
5789
         *slots_qend = (int)(total / request_val);
 
5790
   } else {
 
5791
      *slots = INT_MAX;
 
5792
      *slots_qend = INT_MAX;
 
5793
   }   
 
5794
 
 
5795
   if (*slots == 0 || *slots_qend == 0) {
 
5796
      char dom_str[5];
 
5797
      dstring availability; char availability_text[1024];
 
5798
 
 
5799
      sge_dstring_init(&availability, availability_text, sizeof(availability_text));
 
5800
      
 
5801
      monitor_dominance(dom_str, DOMINANT_TYPE_CONSUMABLE | layer);
 
5802
      sge_dstring_sprintf(&availability, "%s:%s=%f", dom_str, lGetString(request, CE_name), (total - used));
 
5803
      sge_dstring_append(reason, MSG_SCHEDD_ITOFFERSONLY);
 
5804
      sge_dstring_append(reason, availability_text);
 
5805
 
 
5806
      if ((a->duration != DISPATCH_TIME_NOW) &&
 
5807
          (*slots != 0 && *slots_qend == 0)) {
 
5808
         sge_dstring_append(reason, MSG_SCHEDD_DUETORR);
 
5809
      }
 
5810
   }
 
5811
   
 
5812
   DPRINTF(("\t\t%s: ri_slots_by_time: %s=%f has %d (%d) slots at time "sge_U32CFormat"%s (avail: %f total: %f)\n", 
 
5813
         object_name, lGetString(uep, RUE_name), request_val, *slots, *slots_qend, start,
 
5814
           !a->is_reservation?" (= now)":"", total - used, total));
 
5815
 
 
5816
   DRETURN(DISPATCH_OK);
 
5817
}
 
5818
 
 
5819
 
 
5820
/* Determine maximum number of host_slots as limited
 
5821
   by job request to this host 
 
5822
 
 
5823
   for each resource at this host requested by the job {
 
5824
      avail(R) = (total - used) / request
 
5825
   }
 
5826
   host_slot_max_by_R = MIN(all avail(R))
 
5827
 
 
5828
   host_slot = MIN(host_slot_max_by_T, host_slot_max_by_R)
 
5829
 
 
5830
*/
 
5831
dispatch_t
 
5832
parallel_rc_slots_by_time(const sge_assignment_t *a, lList *requests,  int *slots, int *slots_qend, 
 
5833
                 lList *total_list, lList *rue_list, lList *load_attr, bool force_slots, 
 
5834
                 lListElem *queue, u_long32 layer, double lc_factor, u_long32 tag, 
 
5835
                 bool allow_non_requestable, const char *object_name, bool isRQ)
 
5836
{
 
5837
   dstring reason; 
 
5838
   char reason_buf[1024];
 
5839
   int avail = 0;
 
5840
   int avail_qend = 0;
 
5841
   int max_slots = INT_MAX, max_slots_qend = INT_MAX;
 
5842
   const char *name;
 
5843
   static lListElem *implicit_slots_request = NULL;
 
5844
   lListElem *tep, *cep, *actual, *req;
 
5845
   dispatch_t result;
 
5846
 
 
5847
   DENTER(TOP_LAYER, "parallel_rc_slots_by_time");
 
5848
 
 
5849
   sge_dstring_init(&reason, reason_buf, sizeof(reason_buf));
 
5850
 
 
5851
   clear_resource_tags(requests, QUEUE_TAG); 
 
5852
 
 
5853
   if (!implicit_slots_request) {
 
5854
      implicit_slots_request = lCreateElem(CE_Type);
 
5855
      lSetString(implicit_slots_request, CE_name, SGE_ATTR_SLOTS);
 
5856
      lSetString(implicit_slots_request, CE_stringval, "1");
 
5857
      lSetDouble(implicit_slots_request, CE_doubleval, 1);
 
5858
   }
 
5859
 
 
5860
   /* --- implicit slot request */
 
5861
   name = SGE_ATTR_SLOTS;
 
5862
   if (!(tep = lGetElemStr(total_list, CE_name, name)) && force_slots) {
 
5863
      DRETURN(DISPATCH_OK); /* ??? Is this correct? Should be DISPATCH_NEVER_CAT */
 
5864
   }
 
5865
   if (tep) {
 
5866
      if (ri_slots_by_time(a, &avail, &avail_qend, 
 
5867
            rue_list, implicit_slots_request, load_attr, total_list, queue, layer, lc_factor, 
 
5868
            &reason, allow_non_requestable, false, object_name)) {
 
5869
         /* If the request is made from the resource quota module, this error message
 
5870
          * is not informative and should not be displayed */
 
5871
         if (!isRQ) {
 
5872
            schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNINQUEUE_SSS, "slots=1", object_name, reason_buf);
 
5873
         }
 
5874
         DRETURN(DISPATCH_NEVER_CAT);
 
5875
      }
 
5876
      max_slots      = MIN(max_slots,      avail);
 
5877
      max_slots_qend = MIN(max_slots_qend, avail_qend);
 
5878
      DPRINTF(("%s: parallel_rc_slots_by_time(%s) %d (%d later)\n", object_name, name, 
 
5879
            (int)max_slots, (int)max_slots_qend));
 
5880
   }
 
5881
 
 
5882
 
 
5883
   /* --- default request */
 
5884
   for_each (actual, rue_list) {
 
5885
      name = lGetString(actual, RUE_name);
 
5886
      if (!strcmp(name, SGE_ATTR_SLOTS)) {
 
5887
         continue;
 
5888
      }
 
5889
      cep = centry_list_locate(a->centry_list, name);
 
5890
 
 
5891
      if (!is_requested(requests, name)) {
 
5892
         double request;
 
5893
         const char *def_req = lGetString(cep, CE_default);
 
5894
         if (def_req) {
 
5895
            parse_ulong_val(&request, NULL, lGetUlong(cep, CE_valtype), def_req, NULL, 0);
 
5896
 
 
5897
            if (request != 0) {
 
5898
 
 
5899
               lSetString(cep, CE_stringval, def_req);
 
5900
               lSetDouble(cep, CE_doubleval, request);
 
5901
 
 
5902
               if (ri_slots_by_time(a, &avail, &avail_qend, 
 
5903
                        rue_list, cep, load_attr, total_list, queue, layer, lc_factor,   
 
5904
                        &reason, allow_non_requestable, false, object_name)==-1) {
 
5905
                  char buff[1024 + 1];
 
5906
                  centry_list_append_to_string(requests, buff, sizeof(buff) - 1);
 
5907
                  if (*buff && (buff[strlen(buff) - 1] == '\n')) {
 
5908
                     buff[strlen(buff) - 1] = 0;
 
5909
                  }   
 
5910
                  schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNINQUEUE_SSS, buff, object_name, reason_buf);
 
5911
                  DRETURN(DISPATCH_NEVER_CAT);
 
5912
               }
 
5913
               max_slots      = MIN(max_slots,      avail);
 
5914
               max_slots_qend = MIN(max_slots_qend, avail_qend);
 
5915
               DPRINTF(("%s: parallel_rc_slots_by_time(%s) %d (%d later)\n", object_name, name, 
 
5916
                     (int)max_slots, (int)max_slots_qend));
 
5917
            }
 
5918
         }
 
5919
      } 
 
5920
   }
 
5921
 
 
5922
   /* --- explicit requests */
 
5923
   for_each (req, requests) {
 
5924
      name = lGetString(req, CE_name);
 
5925
      result = ri_slots_by_time(a, &avail, &avail_qend, 
 
5926
               rue_list, req, load_attr, total_list, queue, layer, lc_factor,   
 
5927
               &reason, allow_non_requestable, false, object_name);
 
5928
 
 
5929
      if (result == DISPATCH_NEVER_CAT || result == DISPATCH_NEVER_JOB) {
 
5930
         char buff[1024 + 1];
 
5931
         centry_list_append_to_string(requests, buff, sizeof(buff) - 1);
 
5932
         if (*buff && (buff[strlen(buff) - 1] == '\n')) {
 
5933
            buff[strlen(buff) - 1] = 0;
 
5934
         }   
 
5935
         schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNINQUEUE_SSS, buff, object_name, reason_buf);
 
5936
      }
 
5937
      
 
5938
      switch (result) {
 
5939
         case DISPATCH_OK: /* the requested element does not exist */
 
5940
         case DISPATCH_NOT_AT_TIME: /* will match later-on */
 
5941
 
 
5942
            DPRINTF(("%s: explicit request for %s gets us %d slots (%d later)\n", 
 
5943
                  object_name, name, avail, avail_qend));
 
5944
            if (lGetUlong(req, CE_tagged) < tag && tag != RQS_TAG)
 
5945
               lSetUlong(req, CE_tagged, tag);
 
5946
 
 
5947
            max_slots      = MIN(max_slots,      avail);
 
5948
            max_slots_qend = MIN(max_slots_qend, avail_qend);
 
5949
            DPRINTF(("%s: parallel_rc_slots_by_time(%s) %d (%d later)\n", object_name, name, 
 
5950
                  (int)max_slots, (int)max_slots_qend));
 
5951
            break;
 
5952
 
 
5953
         case DISPATCH_NEVER_CAT: /* the requested element does not exist */
 
5954
   
 
5955
            DPRINTF(("%s: parallel_rc_slots_by_time(%s) <never>\n", object_name, name));
 
5956
            *slots = *slots_qend = 0;
 
5957
            DRETURN(DISPATCH_NEVER_CAT);
 
5958
 
 
5959
         case DISPATCH_NEVER_JOB: /* the requested element does not exist */
 
5960
 
 
5961
            DPRINTF(("%s: parallel_rc_slots_by_time(%s) <never>\n", object_name, name));
 
5962
            *slots = *slots_qend = 0;
 
5963
            DRETURN(DISPATCH_NEVER_JOB);
 
5964
 
 
5965
            
 
5966
         case DISPATCH_MISSING_ATTR: /* the requested element does not exist */
 
5967
            if (tag == QUEUE_TAG && lGetUlong(req, CE_tagged) == NO_TAG) {
 
5968
               DPRINTF(("%s: parallel_rc_slots_by_time(%s) <never found>\n", object_name, name));
 
5969
               *slots = *slots_qend = 0;
 
5970
               DRETURN(DISPATCH_NEVER_CAT);
 
5971
            }
 
5972
            DPRINTF(("%s: parallel_rc_slots_by_time(%s) no such resource, but already satisfied\n", 
 
5973
                     object_name, name));
 
5974
            break;
 
5975
         case DISPATCH_NEVER:
 
5976
         default :
 
5977
            DPRINTF(("unexpected return code\n")); 
 
5978
      }
 
5979
   }
 
5980
 
 
5981
   *slots = max_slots;
 
5982
   *slots_qend = max_slots_qend;
 
5983
 
 
5984
   DRETURN(DISPATCH_OK);
 
5985
}
 
5986
 
 
5987
/****** sge_select_queue/sge_create_load_list() ********************************
 
5988
*  NAME
 
5989
*     sge_create_load_list() -- create the controll structure for consumables as
 
5990
*                               load thresholds
 
5991
*
 
5992
*  SYNOPSIS
 
5993
*     void sge_create_load_list(const lList *queue_list, const lList 
 
5994
*     *host_list, const lList *centry_list, lList **load_list) 
 
5995
*
 
5996
*  FUNCTION
 
5997
*     scanes all queues for consumables as load thresholds. It builds a 
 
5998
*     consumable category for each queue which is using consumables as a load
 
5999
*     threshold. 
 
6000
*     If no consumables are used, the *load_list is set to NULL.
 
6001
*
 
6002
*  INPUTS
 
6003
*     const lList *queue_list  - a list of queue instances
 
6004
*     const lList *host_list   - a list of hosts
 
6005
*     const lList *centry_list - a list of complex entries
 
6006
*     lList **load_list        - a ref to the target load list
 
6007
*
 
6008
*  NOTES
 
6009
*     MT-NOTE: sge_create_load_list() is MT safe 
 
6010
*
 
6011
*  SEE ALSO
 
6012
*     sge_create_load_list
 
6013
*     load_locate_elem
 
6014
*     sge_load_list_alarm
 
6015
*     sge_remove_queue_from_load_list
 
6016
*     sge_free_load_list
 
6017
*
 
6018
*******************************************************************************/
 
6019
void sge_create_load_list(const lList *queue_list, const lList *host_list, 
 
6020
                          const lList *centry_list, lList **load_list) {
 
6021
   lListElem *queue;
 
6022
   lListElem *load_threshold;
 
6023
   lListElem *centry;
 
6024
   lList * load_threshold_list;
 
6025
   const char *load_threshold_name;
 
6026
   const char *limit_value;
 
6027
   lListElem *global;
 
6028
   lListElem *host;
 
6029
 
 
6030
   DENTER(TOP_LAYER, "sge_create_load_list");
 
6031
 
 
6032
   if (load_list == NULL){
 
6033
      CRITICAL((SGE_EVENT, "no load_list specified\n"));
 
6034
      DEXIT;
 
6035
      abort();
 
6036
   }
 
6037
 
 
6038
   if (*load_list != NULL){
 
6039
      sge_free_load_list(load_list);
 
6040
   }
 
6041
 
 
6042
   if ((global = host_list_locate(host_list, SGE_GLOBAL_NAME)) == NULL) {
 
6043
      ERROR((SGE_EVENT, "no global host in sge_create_load_list"));
 
6044
      DRETURN_VOID;
 
6045
   }
 
6046
 
 
6047
   for_each(queue, queue_list) {
 
6048
      load_threshold_list = lGetList(queue, QU_load_thresholds);
 
6049
      for_each(load_threshold, load_threshold_list) {
 
6050
         load_threshold_name = lGetString(load_threshold, CE_name);
 
6051
         limit_value = lGetString(load_threshold, CE_stringval);
 
6052
         if ((centry = centry_list_locate(centry_list, load_threshold_name)) == NULL) {
 
6053
            ERROR((SGE_EVENT, MSG_SCHEDD_WHYEXCEEDNOCOMPLEX_S, load_threshold_name));
 
6054
            goto error;
 
6055
         }
 
6056
 
 
6057
         if (lGetBool(centry, CE_consumable)) {
 
6058
            lListElem *global_consumable = NULL;
 
6059
            lListElem *host_consumable = NULL;
 
6060
            lListElem *queue_consumable = NULL;
 
6061
 
 
6062
            lListElem *load_elem = NULL;
 
6063
            lListElem *queue_ref_elem = NULL;
 
6064
            lList *queue_ref_list = NULL;
 
6065
 
 
6066
 
 
6067
            if ((host = host_list_locate(host_list, lGetHost(queue, QU_qhostname))) == NULL){  
 
6068
               ERROR((SGE_EVENT, MSG_SGETEXT_INVALIDHOSTINQUEUE_SS, 
 
6069
                      lGetHost(queue, QU_qhostname), lGetString(queue, QU_full_name)));
 
6070
               goto error;
 
6071
            }
 
6072
 
 
6073
            global_consumable = lGetSubStr(global, RUE_name, load_threshold_name, 
 
6074
                                           EH_resource_utilization);
 
6075
            host_consumable = lGetSubStr(host, RUE_name, load_threshold_name, 
 
6076
                                         EH_resource_utilization);
 
6077
            queue_consumable = lGetSubStr(queue, RUE_name, load_threshold_name, 
 
6078
                                          QU_resource_utilization);
 
6079
 
 
6080
            if (*load_list == NULL) {
 
6081
               *load_list = lCreateList("load_ref_list", LDR_Type);
 
6082
               if (*load_list == NULL) {
 
6083
                  goto error;
 
6084
               }   
 
6085
            }
 
6086
            else {
 
6087
               load_elem = load_locate_elem(*load_list, global_consumable, 
 
6088
                                            host_consumable, queue_consumable,
 
6089
                                            limit_value);
 
6090
            }
 
6091
            if (load_elem == NULL) {
 
6092
               load_elem = lCreateElem(LDR_Type);
 
6093
               if (load_elem == NULL) {
 
6094
                  goto error;
 
6095
               }   
 
6096
               lSetPosRef(load_elem, LDR_global_pos, global_consumable);
 
6097
               lSetPosRef(load_elem, LDR_host_pos, host_consumable);
 
6098
               lSetPosRef(load_elem, LDR_queue_pos, queue_consumable);
 
6099
               lSetPosString(load_elem, LDR_limit_pos, limit_value);
 
6100
               lAppendElem(*load_list, load_elem);
 
6101
            }
 
6102
         
 
6103
            queue_ref_list = lGetPosList(load_elem, LDR_queue_ref_list_pos);
 
6104
            if (queue_ref_list == NULL) {
 
6105
               queue_ref_list = lCreateList("", QRL_Type);
 
6106
               if (queue_ref_list == NULL) {
 
6107
                  goto error;
 
6108
               }   
 
6109
               lSetPosList(load_elem, LDR_queue_ref_list_pos, queue_ref_list);
 
6110
            }
 
6111
               
 
6112
            queue_ref_elem = lCreateElem(QRL_Type);
 
6113
            if (queue_ref_elem == NULL) {
 
6114
               goto error;
 
6115
            }   
 
6116
            lSetRef(queue_ref_elem, QRL_queue, queue);
 
6117
            lAppendElem(queue_ref_list, queue_ref_elem);
 
6118
 
 
6119
            /* reset the changed bit in the consumables */
 
6120
            if (global_consumable != NULL){
 
6121
               sge_bitfield_reset(&(global_consumable->changed));
 
6122
            }
 
6123
            if (host_consumable != NULL){
 
6124
               sge_bitfield_reset(&(host_consumable->changed));
 
6125
            }
 
6126
            if (queue_consumable != NULL){
 
6127
               sge_bitfield_reset(&(queue_consumable->changed));
 
6128
            }
 
6129
 
 
6130
         }
 
6131
      }
 
6132
   }
 
6133
 
 
6134
   DRETURN_VOID;
 
6135
 
 
6136
error:
 
6137
   DPRINTF(("error in sge_create_load_list!"));
 
6138
   ERROR((SGE_EVENT, MSG_SGETEXT_CONSUMABLE_AS_LOAD));
 
6139
   sge_free_load_list(load_list);
 
6140
   DRETURN_VOID;
 
6141
 
 
6142
}
 
6143
 
 
6144
/****** sge_select_queue/load_locate_elem() ************************************
 
6145
*  NAME
 
6146
*     load_locate_elem() -- locates a consumable category in the given load list
 
6147
*
 
6148
*  SYNOPSIS
 
6149
*     static lListElem* load_locate_elem(lList *load_list, lListElem 
 
6150
*     *global_consumable, lListElem *host_consumable, lListElem 
 
6151
*     *queue_consumable) 
 
6152
*
 
6153
*  INPUTS
 
6154
*     lList *load_list             - the load list to work on
 
6155
*     lListElem *global_consumable - a ref to the global consumable
 
6156
*     lListElem *host_consumable   - a ref to the host consumable
 
6157
*     lListElem *queue_consumable  - a ref to the qeue consumable
 
6158
*
 
6159
*  RESULT
 
6160
*     static lListElem* - NULL, or the category element from the load list
 
6161
*
 
6162
*  NOTES
 
6163
*     MT-NOTE: load_locate_elem() is MT safe 
 
6164
*
 
6165
*  SEE ALSO
 
6166
*     sge_create_load_list
 
6167
*     load_locate_elem
 
6168
*     sge_load_list_alarm
 
6169
*     sge_remove_queue_from_load_list
 
6170
*     sge_free_load_list
 
6171
*     
 
6172
*******************************************************************************/
 
6173
static lListElem *load_locate_elem(lList *load_list, lListElem *global_consumable, 
 
6174
                            lListElem *host_consumable, lListElem *queue_consumable,
 
6175
                            const char *limit) {
 
6176
   lListElem *load_elem = NULL;
 
6177
   lListElem *load = NULL;
 
6178
 
 
6179
   for_each(load, load_list) {
 
6180
      if ((lGetPosRef(load, LDR_global_pos) == global_consumable) &&
 
6181
          (lGetPosRef(load, LDR_host_pos) == host_consumable) &&
 
6182
          (lGetPosRef(load, LDR_queue_pos) == queue_consumable) &&
 
6183
          ( strcmp(lGetPosString(load, LDR_limit_pos), limit) == 0)) {
 
6184
         load_elem = load;
 
6185
         break;
 
6186
      }
 
6187
   }
 
6188
   
 
6189
   return load_elem;
 
6190
}
 
6191
 
 
6192
/****** sge_select_queue/sge_load_list_alarm() *********************************
 
6193
*  NAME
 
6194
*     sge_load_list_alarm() -- checks if queues went into an alarm state
 
6195
*
 
6196
*  SYNOPSIS
 
6197
*     bool sge_load_list_alarm(lList *load_list, const lList *host_list, const 
 
6198
*     lList *centry_list) 
 
6199
*
 
6200
*  FUNCTION
 
6201
*     The function uses the cull bitfield to identify modifications in one of
 
6202
*     the consumable elements. If the consumption has changed, the load for all
 
6203
*     queue referencing the consumable is recomputed. If a queue exceeds it
 
6204
*     load threshold, QU_tagged4schedule is set to 1.
 
6205
*
 
6206
*  INPUTS
 
6207
*     lList *load_list         - ??? 
 
6208
*     const lList *host_list   - ??? 
 
6209
*     const lList *centry_list - ??? 
 
6210
*
 
6211
*  RESULT
 
6212
*     bool - true, if at least one queue was set into alarm state 
 
6213
*
 
6214
*  NOTES
 
6215
*     MT-NOTE: sge_load_list_alarm() is MT safe 
 
6216
*
 
6217
*  SEE ALSO
 
6218
*     sge_create_load_list
 
6219
*     load_locate_elem
 
6220
*     sge_load_list_alarm
 
6221
*     sge_remove_queue_from_load_list
 
6222
*     sge_free_load_list
 
6223
*     
 
6224
*******************************************************************************/
 
6225
bool sge_load_list_alarm(lList *load_list, const lList *host_list, 
 
6226
                         const lList *centry_list) {   
 
6227
   lListElem *load;
 
6228
   lListElem *queue;
 
6229
   lListElem *queue_ref;
 
6230
   lList *queue_ref_list;
 
6231
   char reason[2048];
 
6232
   bool is_alarm = false;
 
6233
   
 
6234
   DENTER(TOP_LAYER, "sge_load_list_alarm");
 
6235
 
 
6236
   if (load_list == NULL) {
 
6237
      DRETURN(is_alarm);
 
6238
   }
 
6239
   
 
6240
   for_each(load, load_list) {
 
6241
      bool is_recalc=false;
 
6242
      lListElem * elem;
 
6243
 
 
6244
      elem = lGetPosRef(load, LDR_global_pos);
 
6245
      if (elem != NULL) {
 
6246
         if ( sge_bitfield_changed(&(elem->changed))) {
 
6247
            is_recalc = true;
 
6248
            sge_bitfield_reset(&(elem->changed)); 
 
6249
         }
 
6250
      }
 
6251
      
 
6252
      elem = lGetPosRef(load, LDR_host_pos);
 
6253
      if (elem != NULL) {
 
6254
         if ( sge_bitfield_changed(&(elem->changed))) {
 
6255
            is_recalc = true;
 
6256
            sge_bitfield_reset(&(elem->changed)); 
 
6257
         }
 
6258
      }
 
6259
      
 
6260
      elem = lGetPosRef(load, LDR_queue_pos);
 
6261
      if (elem != NULL) {
 
6262
         if ( sge_bitfield_changed(&(elem->changed))) {
 
6263
            is_recalc = true;
 
6264
            sge_bitfield_reset(&(elem->changed)); 
 
6265
         }
 
6266
      }
 
6267
     
 
6268
      if (is_recalc) {
 
6269
         bool is_category_alarm = false;
 
6270
         queue_ref_list = lGetPosList(load, LDR_queue_ref_list_pos);
 
6271
         for_each(queue_ref, queue_ref_list) {
 
6272
            queue = lGetRef(queue_ref, QRL_queue);
 
6273
            if (is_category_alarm) {
 
6274
               lSetUlong(queue, QU_tagged4schedule, 1); 
 
6275
            }
 
6276
            else if (sge_load_alarm(reason, queue, lGetList(queue, QU_load_thresholds), host_list, 
 
6277
                               centry_list, NULL, true)) {
 
6278
 
 
6279
               DPRINTF(("queue %s tagged to be overloaded: %s\n", 
 
6280
                                     lGetString(queue, QU_full_name), reason));
 
6281
               schedd_mes_add_global(SCHEDD_INFO_QUEUEOVERLOADED_SS, 
 
6282
                                     lGetString(queue, QU_full_name), reason);
 
6283
               lSetUlong(queue, QU_tagged4schedule, 1); 
 
6284
               is_alarm = true;
 
6285
               is_category_alarm = true;
 
6286
            }
 
6287
            else {
 
6288
               break;
 
6289
            }
 
6290
         }
 
6291
      }
 
6292
   }
 
6293
   
 
6294
   DRETURN(is_alarm); 
 
6295
}
 
6296
 
 
6297
/****** sge_select_queue/sge_remove_queue_from_load_list() *********************
 
6298
*  NAME
 
6299
*     sge_remove_queue_from_load_list() -- removes queues from the load list 
 
6300
*
 
6301
*  SYNOPSIS
 
6302
*     void sge_remove_queue_from_load_list(lList **load_list, const lList 
 
6303
*     *queue_list) 
 
6304
*
 
6305
*  INPUTS
 
6306
*     lList **load_list       - load list structure
 
6307
*     const lList *queue_list - queues to be removed from it.
 
6308
*
 
6309
*  NOTES
 
6310
*     MT-NOTE: sge_remove_queue_from_load_list() is MT safe 
 
6311
*
 
6312
*  SEE ALSO
 
6313
*     sge_create_load_list
 
6314
*     load_locate_elem
 
6315
*     sge_load_list_alarm
 
6316
*     sge_remove_queue_from_load_list
 
6317
*     sge_free_load_list
 
6318
*     
 
6319
*******************************************************************************/
 
6320
void sge_remove_queue_from_load_list(lList **load_list, const lList *queue_list){
 
6321
   lListElem* queue = NULL;
 
6322
   lListElem *load = NULL;
 
6323
   
 
6324
   DENTER(TOP_LAYER, "sge_remove_queue_from_load_list");
 
6325
   
 
6326
   if (load_list == NULL){
 
6327
      CRITICAL((SGE_EVENT, "no load_list specified\n"));
 
6328
      DEXIT;
 
6329
      abort();
 
6330
   }
 
6331
 
 
6332
   if (*load_list == NULL) {
 
6333
      DRETURN_VOID;
 
6334
   }
 
6335
 
 
6336
   for_each(queue, queue_list) {
 
6337
      bool is_found = false;
 
6338
      lList *queue_ref_list = NULL;
 
6339
      lListElem *queue_ref = NULL;
 
6340
   
 
6341
      for_each(load, *load_list) {
 
6342
         queue_ref_list = lGetPosList(load, LDR_queue_ref_list_pos);
 
6343
         for_each(queue_ref, queue_ref_list) {
 
6344
            if (queue == lGetRef(queue_ref, QRL_queue)) {
 
6345
               is_found = true;
 
6346
               break;
 
6347
            }
 
6348
         }
 
6349
         if (is_found) {
 
6350
            lRemoveElem(queue_ref_list, &queue_ref);
 
6351
 
 
6352
            if (lGetNumberOfElem(queue_ref_list) == 0) {
 
6353
               lRemoveElem(*load_list, &load);
 
6354
            }            
 
6355
            break;
 
6356
         }
 
6357
      }
 
6358
 
 
6359
      if (lGetNumberOfElem(*load_list) == 0) {
 
6360
         lFreeList(load_list);
 
6361
         DRETURN_VOID;
 
6362
      }
 
6363
   }
 
6364
 
 
6365
   DRETURN_VOID;
 
6366
}
 
6367
 
 
6368
 
 
6369
/****** sge_select_queue/sge_free_load_list() **********************************
 
6370
*  NAME
 
6371
*     sge_free_load_list() -- frees the load list and sets it to NULL
 
6372
*
 
6373
*  SYNOPSIS
 
6374
*     void sge_free_load_list(lList **load_list) 
 
6375
*
 
6376
*  INPUTS
 
6377
*     lList **load_list - the load list
 
6378
*
 
6379
*  NOTES
 
6380
*     MT-NOTE: sge_free_load_list() is MT safe 
 
6381
*
 
6382
*  SEE ALSO
 
6383
*     sge_create_load_list
 
6384
*     load_locate_elem
 
6385
*     sge_load_list_alarm
 
6386
*     sge_remove_queue_from_load_list
 
6387
*     sge_free_load_list
 
6388
*     
 
6389
*******************************************************************************/
 
6390
void sge_free_load_list(lList **load_list)
 
6391
{
 
6392
   DENTER(TOP_LAYER, "sge_free_load_list");
 
6393
 
 
6394
   lFreeList(load_list);
 
6395
   
 
6396
   DRETURN_VOID;
 
6397
}
 
6398
 
 
6399
#ifdef SGE_PQS_API
 
6400
 
 
6401
typedef struct lib_cache_s {
 
6402
   char *key;
 
6403
   char *lib_name;
 
6404
   char *fn_name;
 
6405
   void *lib_handle;
 
6406
   void *fn_handle;
 
6407
   struct lib_cache_s *next;
 
6408
} lib_cache_t;
 
6409
 
 
6410
/****** sge_dlib() *************************************************************
 
6411
*  NAME
 
6412
*     sge_dlib() -- lookup, load, and cache function from a dynamic library
 
6413
*
 
6414
*  SYNOPSIS
 
6415
*     void *sge_dlib(const char *key, const char *lib_name, const char *fn_name,
 
6416
*                    lib_cache_t **lib_cache_list)
 
6417
*
 
6418
*  INPUTS
 
6419
*     const char *key - unique key for identifying function
 
6420
*     const char *lib_name - dynamic library name
 
6421
*     const char *fn_nam - function name
 
6422
*     lib_cache_t **lib_cache_list - cache list (if NULL, we use a global cache)
 
6423
*
 
6424
*  RETURNS
 
6425
*     void * - the address of the function
 
6426
*
 
6427
*  NOTES
 
6428
*     MT-NOTE: sge_free_load_list() is not MT safe 
 
6429
*
 
6430
*  SEE ALSO
 
6431
*     
 
6432
*******************************************************************************/
 
6433
void *
 
6434
sge_dlib(const char *key, const char *lib_name, const char *fn_name,
 
6435
         lib_cache_t **lib_cache_list)
 
6436
{
 
6437
   static lib_cache_t *static_lib_cache_list = NULL;
 
6438
   lib_cache_t **cache_list = NULL;
 
6439
   lib_cache_t *cache = NULL;
 
6440
   lib_cache_t *prev = NULL;
 
6441
   lib_cache_t *new_cache = NULL;
 
6442
   int replace = 0;
 
6443
   void *new_lib_handle = NULL;
 
6444
   void *new_fn_handle = NULL; 
 
6445
   const char *error = NULL;
 
6446
 
 
6447
   DENTER(TOP_LAYER, "sge_dlib");
 
6448
 
 
6449
   /* Use user cache list if supplied */
 
6450
   if (lib_cache_list)
 
6451
      cache_list = lib_cache_list;
 
6452
   else
 
6453
      cache_list = &static_lib_cache_list;
 
6454
 
 
6455
   /*
 
6456
    * Search based on supplied key. If found and the library name and function
 
6457
    * name match, return the function address. If the library or function
 
6458
    * do not match, then we will reload the library.
 
6459
    */
 
6460
   for (cache=*cache_list; cache; prev=cache, cache=cache->next) {
 
6461
      if (strcmp(key, cache->key)==0) {
 
6462
         if (strcmp(lib_name, cache->lib_name)==0 &&
 
6463
             strcmp(fn_name, cache->fn_name)==0) {
 
6464
            DRETURN(cache->fn_handle);
 
6465
         } else {
 
6466
            replace=1;
 
6467
            break;
 
6468
         }
 
6469
      }
 
6470
   }
 
6471
 
 
6472
   /* open the library */
 
6473
   new_lib_handle = dlopen(lib_name, RTLD_LAZY);
 
6474
   if (!new_lib_handle) {
 
6475
      error = dlerror();
 
6476
      ERROR((SGE_EVENT, "Unable to open library %s for %s - %s\n",
 
6477
             lib_name, key, error));
 
6478
      DRETURN(NULL);
 
6479
   }
 
6480
 
 
6481
   /* search library for the function name */
 
6482
   new_fn_handle = dlsym(new_lib_handle, fn_name);
 
6483
   if (((error = dlerror()) != NULL) || !new_fn_handle) {
 
6484
      dlclose(new_lib_handle);
 
6485
      ERROR((SGE_EVENT, "Unable to locate function %s in library %s for %s - %s\n",
 
6486
             fn_name, lib_name, key, error));
 
6487
      DRETURN(NULL);
 
6488
   }
 
6489
 
 
6490
   /* If we're replacing the old function, just delete it */
 
6491
   if (replace) {
 
6492
      dlclose(cache->lib_handle);
 
6493
      FREE(cache->key);
 
6494
      FREE(cache->lib_name);
 
6495
      FREE(cache->fn_name);
 
6496
      if (prev == NULL) {
 
6497
         *cache_list = cache->next;
 
6498
      }   
 
6499
      else {
 
6500
         prev->next = cache->next;
 
6501
      }   
 
6502
      FREE(cache);
 
6503
   }
 
6504
 
 
6505
   /* cache the new function address */
 
6506
   if ((new_cache = (lib_cache_t *)malloc(sizeof(lib_cache_t))) == NULL ||
 
6507
       (new_cache->key = strdup(key)) == NULL ||
 
6508
       (new_cache->lib_name = strdup(lib_name)) == NULL ||
 
6509
       (new_cache->fn_name = strdup(fn_name)) == NULL) {
 
6510
      ERROR((SGE_EVENT, "Memory allocation problem in sge_dl\n"));
 
6511
      DRETURN(NULL);
 
6512
   }
 
6513
   new_cache->lib_handle = new_lib_handle;
 
6514
   new_cache->fn_handle = new_fn_handle;
 
6515
   new_cache->next = *cache_list;
 
6516
   *cache_list = new_cache;
 
6517
 
 
6518
   /* return the cached function address */
 
6519
   DRETURN(new_cache->fn_handle);
 
6520
}
 
6521
 
 
6522
static void
 
6523
strcpy_replace(char *dp, const char *sp, lList *rlist)
 
6524
{
 
6525
   char *name = NULL;
 
6526
   int done = 0;
 
6527
   int curly = 0;
 
6528
   const char *es = NULL;
 
6529
 
 
6530
   if (rlist == NULL) {
 
6531
      strcpy(dp, sp);
 
6532
      return;
 
6533
   }
 
6534
 
 
6535
   while (!done) {
 
6536
      if (*sp == 0) /* done means we make one last pass */
 
6537
         done = 1;
 
6538
      if (name && !isalnum(*sp) && *sp != '_') {
 
6539
         lListElem *res;
 
6540
         const char *s = "";
 
6541
         *dp = 0;
 
6542
         if ((res = lGetElemStr(rlist, CE_name, name)))
 
6543
            s = lGetString(res, CE_stringval);
 
6544
         /* handle ${varname} */
 
6545
         if (curly && *sp == '}')
 
6546
            sp++;
 
6547
         /* handle ${varname:-value} and ${varname:+value} */
 
6548
         else if (curly && *sp == ':') {
 
6549
            if (sp[1] == '-' || sp[1] == '+') {
 
6550
               const char *ep;
 
6551
               for (ep=sp+2; *ep; ep++) {
 
6552
                  if (*ep == '}') {
 
6553
                     if ((!*s && sp[1] == '-') ||
 
6554
                         (*s  && sp[1] == '+')) {
 
6555
                        s = sp+2;   /* mark substition string */
 
6556
                        es = ep;    /* mark end of substition string */
 
6557
                     }
 
6558
                     sp = ep+1;  /* point past varname */
 
6559
                     break;
 
6560
                  }
 
6561
               }
 
6562
            }
 
6563
         }
 
6564
         dp = name;
 
6565
         while (*s && s != es)
 
6566
            *dp++ = *s++;
 
6567
         name = NULL;
 
6568
         *dp = 0;
 
6569
         curly = 0;
 
6570
         es = NULL;
 
6571
      } else if (*sp == '$') {
 
6572
         sp++;
 
6573
         name = dp;
 
6574
         if (*sp == '{') {
 
6575
            curly = 1;
 
6576
            sp++;
 
6577
         }
 
6578
      } else
 
6579
         *dp++ = *sp++;
 
6580
   }
 
6581
}
 
6582
 
 
6583
/****** sge_select_queue/sge_call_pe_qsort() **********************************
 
6584
*  NAME
 
6585
*     sge_call_pe_qsort() -- call the Parallel Environment qsort plug-in
 
6586
*
 
6587
*  SYNOPSIS
 
6588
*     void sge_call_pe_qsort(sge_assignment_t *a, const char *qsort_args)
 
6589
*
 
6590
*  INPUTS
 
6591
*     sge_assignment_t *a - PE assignment
 
6592
*     qsort_args - the PE qsort_args attribute
 
6593
*
 
6594
*  NOTES
 
6595
*     MT-NOTE: sge_call_pe_qsort() is not MT safe 
 
6596
*
 
6597
*  SEE ALSO
 
6598
*     
 
6599
*******************************************************************************/
 
6600
static int
 
6601
sge_call_pe_qsort(sge_assignment_t *a, const char *qsort_args)
 
6602
{
 
6603
   int ret = 0;
 
6604
   struct saved_vars_s *cntx = NULL;
 
6605
   char *tok;
 
6606
   int argc = 0;
 
6607
   pqs_qsort_t pqs_qsort;
 
6608
   const char *pe_name = a->pe_name;
 
6609
   const char *lib_name;
 
6610
   const char *fn_name;
 
6611
   int num_queues = lGetNumberOfElem(a->queue_list);
 
6612
   char qsort_args_buf[4096];
 
6613
   const char *qsort_argv[1024];
 
6614
   char err_str[1024];
 
6615
 
 
6616
   DENTER(TOP_LAYER, "sge_call_pe_qsort");
 
6617
 
 
6618
   err_str[0] = 0;
 
6619
 
 
6620
   /*
 
6621
    * Copy qsort_args substituting any references to $<resource>
 
6622
    * with the corresponding requested value from the hard resource
 
6623
    * list of the job.
 
6624
    */
 
6625
 
 
6626
   strcpy_replace(qsort_args_buf, qsort_args, lGetList(a->job, JB_hard_resource_list));
 
6627
 
 
6628
   if ((lib_name = sge_strtok_r(qsort_args_buf, " ", &cntx)) &&
 
6629
       (fn_name = sge_strtok_r(NULL, " ", &cntx)) &&
 
6630
       (pqs_qsort = sge_dlib(pe_name, lib_name, fn_name, NULL))) {
 
6631
 
 
6632
      pqs_params_t pqs_params;
 
6633
      pqs_queue_t *qp;
 
6634
      lListElem *q;
 
6635
 
 
6636
      /*
 
6637
       * Build queue sort parameters
 
6638
       */
 
6639
      pqs_params.job_id = a->job_id;
 
6640
      pqs_params.task_id = a->ja_task_id;
 
6641
      pqs_params.slots = a->slots;
 
6642
      pqs_params.pe_name = pe_name;
 
6643
      pqs_params.pe_qsort_args = qsort_args_buf;
 
6644
      pqs_params.pe_qsort_argv = qsort_argv;
 
6645
      pqs_params.num_queues = num_queues;
 
6646
      pqs_params.qlist = (pqs_queue_t *)malloc(num_queues * sizeof(pqs_queue_t));
 
6647
 
 
6648
      qp = pqs_params.qlist;
 
6649
      for_each(q, a->queue_list) {
 
6650
         qp->queue_name = lGetString(q, QU_qname);
 
6651
         qp->host_name = lGetHost(q, QU_qhostname);
 
6652
         qp->host_seqno = lGetUlong(q, QU_host_seq_no);
 
6653
         qp->queue_seqno = lGetUlong(q, QU_seq_no);
 
6654
         qp->available_slots = lGetUlong(q, QU_tag);
 
6655
         qp->soft_violations = lGetUlong(q, QU_soft_violation);
 
6656
         qp->new_seqno = 0;
 
6657
         qp++;
 
6658
      }
 
6659
 
 
6660
      /*
 
6661
       * For convenience, convert qsort_args into an argument vector qsort_argv.
 
6662
       */
 
6663
      qsort_argv[argc++] = lib_name;
 
6664
      qsort_argv[argc++] = fn_name;
 
6665
      while ((tok = sge_strtok_r(NULL, " ", &cntx)) &&
 
6666
             argc<(sizeof(qsort_argv)/sizeof(char *)-1)) {
 
6667
         qsort_argv[argc++] = tok;
 
6668
      }
 
6669
 
 
6670
      /*
 
6671
       * Call the dynamic queue sort function
 
6672
       */
 
6673
 
 
6674
      ret = (*pqs_qsort)(&pqs_params, 0, err_str, sizeof(err_str)-1);
 
6675
 
 
6676
      if (err_str[0]) {
 
6677
         ERROR((SGE_EVENT, err_str));
 
6678
      }   
 
6679
 
 
6680
      /*
 
6681
       * Update the queue list with the new sort order
 
6682
       */
 
6683
 
 
6684
      if (ret == PQS_ASSIGNED) {
 
6685
         qp = pqs_params.qlist;
 
6686
         for_each(q, a->queue_list) {
 
6687
            lSetUlong(q, QU_host_seq_no, qp->new_seqno);
 
6688
            qp++;
 
6689
         }
 
6690
      }
 
6691
 
 
6692
      FREE(pqs_params.qlist);
 
6693
   } 
 
6694
   else {
 
6695
      ERROR((SGE_EVENT, "Unable to dynamically load PE qsort_args %s\n", qsort_args));
 
6696
      ret = 0; /* schedule anyway with normal queue/host sort */
 
6697
   }
 
6698
 
 
6699
   if (cntx) {
 
6700
      sge_free_saved_vars(cntx);
 
6701
   }   
 
6702
 
 
6703
   DRETURN(ret);
 
6704
}
 
6705
#endif
 
6706
 
 
6707
/****** sge_select_queue/match_static_advance_reservation() ********************
 
6708
*  NAME
 
6709
*     match_static_advance_reservation() -- Do matching that depends not on queue
 
6710
*                                           or host
 
6711
*
 
6712
*  SYNOPSIS
 
6713
*     static dispatch_t match_static_advance_reservation(const sge_assignment_t 
 
6714
*     *a) 
 
6715
*
 
6716
*  FUNCTION
 
6717
*     Checks whether a job that requests a advance reservation can be scheduled.
 
6718
*     The job can be scheduled if the advance reservation is in state "running".
 
6719
*
 
6720
*  INPUTS
 
6721
*     const sge_assignment_t *a - assignment to match
 
6722
*
 
6723
*  RESULT
 
6724
*     static dispatch_t - DISPATCH_OK on success
 
6725
*                         DISPATCH_NEVER_CAT on error
 
6726
*
 
6727
*  NOTES
 
6728
*     MT-NOTE: match_static_advance_reservation() is MT safe 
 
6729
*******************************************************************************/
 
6730
static dispatch_t match_static_advance_reservation(const sge_assignment_t *a)
 
6731
{
 
6732
   dispatch_t result = DISPATCH_OK;
 
6733
   lListElem *ar;
 
6734
   u_long32 ar_id = lGetUlong(a->job, JB_ar);
 
6735
 
 
6736
   DENTER(TOP_LAYER, "match_static_advance_reservation");
 
6737
 
 
6738
 
 
6739
   if (ar_id != 0) {
 
6740
      if ((ar = lGetElemUlong(a->ar_list, AR_id, ar_id)) != NULL) {
 
6741
         lList *acl_list;
 
6742
 
 
6743
         if (!(a->is_job_verify)) {
 
6744
            /* is ar in error and error handling is not soft? */
 
6745
            if (lGetUlong(ar, AR_state) == AR_ERROR && lGetUlong(ar, AR_error_handling) != 0) {
 
6746
               schedd_mes_add(a->job_id, SCHEDD_INFO_ARISINERROR_I, ar_id); 
 
6747
               DRETURN(DISPATCH_NEVER_CAT);
 
6748
            }
 
6749
            
 
6750
            /* is ar running? */
 
6751
            if (lGetUlong(ar, AR_state) != AR_RUNNING && lGetUlong(ar, AR_state) != AR_ERROR) {
 
6752
               schedd_mes_add(a->job_id, SCHEDD_INFO_EXECTIME_); 
 
6753
               DRETURN(DISPATCH_NEVER_CAT);
 
6754
            }
 
6755
         }
 
6756
 
 
6757
         /* has user access? */
 
6758
         if ((acl_list = lGetList(ar, AR_xacl_list))) {
 
6759
            lListElem *acl_ep;
 
6760
            for_each(acl_ep, acl_list) {
 
6761
               const char* user = lGetString(acl_ep, ARA_name);
 
6762
 
 
6763
               if (!is_hgroup_name(user)) {
 
6764
                  if (strcmp(a->user, user) == 0) {
 
6765
                     break;
 
6766
                  }
 
6767
               } else {
 
6768
                  /* skip preattached \@ sign */
 
6769
                  const char *acl_name = ++user;
 
6770
                  lListElem *userset_list = lGetElemStr(a->acl_list, US_name, acl_name);
 
6771
 
 
6772
                  if (sge_contained_in_access_list(a->user, a->group, userset_list, NULL) == 1) {
 
6773
                     break;
 
6774
                  }
 
6775
               }
 
6776
            }
 
6777
            if (acl_ep != NULL){
 
6778
               dstring buffer = DSTRING_INIT;
 
6779
               sge_dstring_sprintf(&buffer, sge_U32CFormat, sge_u32c(ar_id));
 
6780
               schedd_mes_add(a->job_id, SCHEDD_INFO_HASNOPERMISSION_SS, SGE_OBJ_AR, sge_dstring_get_string(&buffer)); 
 
6781
               sge_dstring_free(&buffer);
 
6782
               DRETURN(DISPATCH_NEVER_CAT);
 
6783
            }
 
6784
         }
 
6785
         
 
6786
         if ((acl_list = lGetList(ar, AR_acl_list))) {
 
6787
            lListElem *acl_ep;
 
6788
            for_each(acl_ep, acl_list) {
 
6789
               const char *user = lGetString(acl_ep, ARA_name);
 
6790
 
 
6791
               if (!is_hgroup_name(user)) {
 
6792
                  if (strcmp(a->user, user) == 0) {
 
6793
                     break;
 
6794
                  }
 
6795
               } else {
 
6796
                  /* skip preattached \@ sign */
 
6797
                  const char *acl_name = ++user;
 
6798
                  lListElem *userset_list = lGetElemStr(a->acl_list, US_name, acl_name);
 
6799
 
 
6800
                  if (sge_contained_in_access_list(a->user, a->group, userset_list, NULL) == 1) {
 
6801
                     break;
 
6802
                  }
 
6803
               }
 
6804
            }
 
6805
            if (acl_ep == NULL){
 
6806
               dstring buffer = DSTRING_INIT;
 
6807
               sge_dstring_sprintf(&buffer, sge_U32CFormat, sge_u32c(ar_id));
 
6808
               schedd_mes_add(a->job_id, SCHEDD_INFO_HASNOPERMISSION_SS, SGE_OBJ_AR, sge_dstring_get_string(&buffer)); 
 
6809
               sge_dstring_free(&buffer);
 
6810
               DRETURN(DISPATCH_NEVER_CAT);
 
6811
            }
 
6812
         }
 
6813
      } else {
 
6814
         /* should never happen */
 
6815
         DRETURN(DISPATCH_NEVER_CAT);
 
6816
      }
 
6817
   }
 
6818
 
 
6819
   DRETURN(result); 
 
6820
}