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

« back to all changes in this revision

Viewing changes to source/libs/sched/sge_resource_quota_schedd.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
 
 
33
#include <string.h>
 
34
#include <limits.h>
 
35
 
 
36
#include "sched/sge_select_queue.h"
 
37
#include "sched/sge_resource_quota_schedd.h"
 
38
#include "sched/sge_resource_utilizationL.h"
 
39
#include "sgeobj/sge_centry.h"
 
40
#include "sgeobj/sge_strL.h"
 
41
#include "sgeobj/sge_jobL.h"
 
42
#include "sgeobj/sge_ctL.h"
 
43
#include "sgeobj/sge_cqueueL.h"
 
44
 
 
45
#include "sgeobj/sge_resource_quota.h"
 
46
#include "sgeobj/sge_object.h"
 
47
#include "uti/sge_hostname.h"
 
48
#include "sge_complex_schedd.h"
 
49
#include "sgeobj/sge_job.h"
 
50
#include "sgeobj/sge_pe.h"
 
51
#include "sgeobj/sge_host.h"
 
52
#include "sgermon.h"
 
53
#include "sched/sort_hosts.h"
 
54
#include "sge_log.h"
 
55
#include "sched/sge_schedd_text.h"
 
56
#include "sched/schedd_message.h"
 
57
#include "uti/sge_parse_num_par.h"
 
58
 
 
59
 
 
60
static void rqs_can_optimize(const lListElem *rule, bool *host, bool *queue, sge_assignment_t *a);
 
61
 
 
62
static void rqs_expand_cqueues(const lListElem *rule, sge_assignment_t *a);
 
63
static void rqs_expand_hosts(const lListElem *rule, sge_assignment_t *a);
 
64
 
 
65
static bool is_cqueue_global(const lListElem *rule);
 
66
static bool is_host_global(const lListElem *rule);
 
67
 
 
68
static bool is_cqueue_expand(const lListElem *rule);
 
69
static bool is_host_expand(const lListElem *rule);
 
70
 
 
71
static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a);
 
72
static bool host_shadowed(const lListElem *rule, sge_assignment_t *a);
 
73
 
 
74
static void rqs_excluded_hosts(const lListElem *rule, sge_assignment_t *a);
 
75
static void rqs_excluded_cqueues(const lListElem *rule, sge_assignment_t *a);
 
76
 
 
77
 
 
78
/****** sge_resource_quota_schedd/rqs_set_dynamical_limit() ***********************
 
79
*  NAME
 
80
*     rqs_set_dynamical_limit() -- evaluate dynamical limit
 
81
*
 
82
*  SYNOPSIS
 
83
*     bool rqs_set_dynamical_limit(lListElem *limit, lListElem 
 
84
*     *global_host, lListElem *exec_host, lList *centry) 
 
85
*
 
86
*  FUNCTION
 
87
*     The function evaluates if neccessary the dynamical limit for a host and
 
88
*     sets the evaluated double value in the given limitation element (RQRL_dvalue).
 
89
*
 
90
*     A evaluation is neccessary if the limit boolean RQRL_dynamic is true. This
 
91
*     field is set by qmaster during the rule set verification
 
92
*
 
93
*  INPUTS
 
94
*     lListElem *limit       - limitation (RQRL_Type)
 
95
*     lListElem *global_host - global host (EH_Type)
 
96
*     lListElem *exec_host   - exec host (EH_Type)
 
97
*     lList *centry          - consumable resource list (CE_Type)
 
98
*
 
99
*  RESULT
 
100
*     bool - always true
 
101
*
 
102
*  NOTES
 
103
*     MT-NOTE: rqs_set_dynamical_limit() is MT safe 
 
104
*
 
105
*******************************************************************************/
 
106
bool
 
107
rqs_set_dynamical_limit(lListElem *limit, lListElem *global_host, lListElem *exec_host, lList *centry) {
 
108
 
 
109
   DENTER(TOP_LAYER, "rqs_set_dynamical_limit");
 
110
 
 
111
   if (lGetBool(limit, RQRL_dynamic)) {
 
112
      double dynamic_limit = scaled_mixed_load(lGetString(limit, RQRL_value), global_host, exec_host, centry);
 
113
      DPRINTF(("found a dynamic limit for host %s with value %d\n", lGetHost(exec_host, EH_name), (int)dynamic_limit));
 
114
      lSetDouble(limit, RQRL_dvalue, dynamic_limit);
 
115
   } 
 
116
 
 
117
   DRETURN(true);
 
118
}
 
119
 
 
120
/****** sge_resource_quota_schedd/rqs_match_assignment() ***********************
 
121
*  NAME
 
122
*     rqs_match_assignment() -- match resource quota rule any queue instance
 
123
*
 
124
*  SYNOPSIS
 
125
*     static bool rqs_match_assignment(const lListElem *rule, sge_assignment_t 
 
126
*     *a) 
 
127
*
 
128
*  FUNCTION
 
129
*     Check whether a resource quota rule can match any queue instance. If
 
130
*     if does not match due to users/projects/pes scope one can rule this
 
131
*     out.
 
132
*    
 
133
*     Note: As long as rqs_match_assignment() is not used for parallel jobs
 
134
*           passing NULL as PE request is perfectly fine.
 
135
*
 
136
*  INPUTS
 
137
*     const lListElem *rule - Resource quota rule
 
138
*     sge_assignment_t *a   - Scheduler assignment 
 
139
*
 
140
*  RESULT
 
141
*     static bool - True if it matches 
 
142
*
 
143
*  NOTES
 
144
*     MT-NOTE: rqs_match_assignment() is MT safe 
 
145
*******************************************************************************/
 
146
static bool rqs_match_assignment(const lListElem *rule, sge_assignment_t *a)
 
147
{
 
148
   return (rqs_filter_match(lGetObject(rule, RQR_filter_projects), FILTER_PROJECTS, a->project, NULL, NULL, NULL) &&
 
149
           rqs_filter_match(lGetObject(rule, RQR_filter_users), FILTER_USERS, a->user, a->acl_list, NULL, a->group) &&
 
150
           rqs_filter_match(lGetObject(rule, RQR_filter_pes), FILTER_PES, NULL, NULL, NULL, NULL))?true:false;
 
151
}
 
152
 
 
153
 
 
154
/****** sge_resource_quota_schedd/cqueue_shadowed() ****************************
 
155
*  NAME
 
156
*     cqueue_shadowed() -- Check for cluster queue rule before current rule
 
157
*
 
158
*  SYNOPSIS
 
159
*     static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a)
 
160
*
 
161
*  FUNCTION
 
162
*     Check whether there is any cluster queue specific rule before the
 
163
*     current rule.
 
164
*
 
165
*  INPUTS
 
166
*     const lListElem *rule - Current rule
 
167
*     sge_assignment_t *a   - Scheduler assignment
 
168
*
 
169
*  RESULT
 
170
*     static bool - True if shadowed
 
171
*
 
172
*  EXAMPLE
 
173
*     limit queue Q001 to F001=1
 
174
*     limit host gridware to F001=0  (--> returns 'true' due to 'Q001' meaning
 
175
*                               that gridware can't be generelly ruled out )
 
176
*
 
177
*  NOTES
 
178
*     MT-NOTE: cqueue_shadowed() is MT safe
 
179
*******************************************************************************/
 
180
static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a)
 
181
{
 
182
   while ((rule = lPrev(rule))) {
 
183
      if (rqs_match_assignment(rule, a) && !is_cqueue_global(rule)) {
 
184
         return true;
 
185
      }
 
186
   }
 
187
   return false;
 
188
}
 
189
 
 
190
/****** sge_resource_quota_schedd/host_shadowed() ******************************
 
191
*  NAME
 
192
*     host_shadowed() -- Check for host rule before current rule
 
193
*
 
194
*  SYNOPSIS
 
195
*     static bool host_shadowed(const lListElem *rule, sge_assignment_t *a)
 
196
*
 
197
*  FUNCTION
 
198
*     Check whether there is any host specific rule before the
 
199
*     current rule.
 
200
*
 
201
*  INPUTS
 
202
*     const lListElem *rule - Current rule
 
203
*     sge_assignment_t *a   - Scheduler assignment
 
204
*
 
205
*  RESULT
 
206
*     static bool - True if shadowed
 
207
*
 
208
*  EXAMPLE
 
209
*     limit host gridware to F001=1
 
210
*     limit queue Q001 to F001=0  (--> returns 'true' due to 'gridware' meaning
 
211
*                               that Q001 can't be generelly ruled out )
 
212
*
 
213
*  NOTES
 
214
*     MT-NOTE: host_shadowed() is MT safe
 
215
*******************************************************************************/
 
216
static bool host_shadowed(const lListElem *rule, sge_assignment_t *a)
 
217
{
 
218
   while ((rule = lPrev(rule))) {
 
219
      if (rqs_match_assignment(rule, a) && !is_host_global(rule)) {
 
220
         return true;
 
221
      }
 
222
   }
 
223
   return false;
 
224
}
 
225
 
 
226
/****** sge_resource_quota_schedd/cqueue_shadowed_by() *************************
 
227
*  NAME
 
228
*     cqueue_shadowed_by() -- Check rules shadowing current cluster queue rule
 
229
*
 
230
*  SYNOPSIS
 
231
*     static bool cqueue_shadowed_by(const char *cqname, const lListElem *rule,
 
232
*     sge_assignment_t *a)
 
233
*
 
234
*  FUNCTION
 
235
*     Check if cluster queue in current rule is shadowed.
 
236
*
 
237
*  INPUTS
 
238
*     const char *cqname    - Cluster queue name to check
 
239
*     const lListElem *rule - Current rule
 
240
*     sge_assignment_t *a   - Assignment
 
241
*
 
242
*  RESULT
 
243
*     static bool - True if shadowed
 
244
*
 
245
*  EXAMPLE
 
246
*     limits queues Q001,Q002 to F001=1
 
247
*     limits queues Q002,Q003 to F001=1 (--> returns 'true' for Q002 and 'false' for Q003)
 
248
*
 
249
*  NOTES
 
250
*     MT-NOTE: cqueue_shadowed_by() is MT safe
 
251
*******************************************************************************/
 
252
static bool cqueue_shadowed_by(const char *cqname, const lListElem *rule, sge_assignment_t *a)
 
253
{
 
254
   while ((rule = lPrev(rule))) {
 
255
      if (rqs_match_assignment(rule, a) &&
 
256
          rqs_filter_match(lGetObject(rule, RQR_filter_queues), FILTER_QUEUES, cqname, NULL, NULL, NULL)) {
 
257
         return true;
 
258
      }
 
259
   }
 
260
 
 
261
   return false;
 
262
}
 
263
 
 
264
/****** sge_resource_quota_schedd/host_shadowed_by() ***************************
 
265
*  NAME
 
266
*     host_shadowed_by() -- ???
 
267
*
 
268
*  SYNOPSIS
 
269
*     static bool host_shadowed_by(const char *host, const lListElem *rule,
 
270
*     sge_assignment_t *a)
 
271
*
 
272
*  FUNCTION
 
273
*     Check if host in current rule is shadowed.
 
274
*
 
275
*  INPUTS
 
276
*     const char *cqname    - Host name to check
 
277
*     const lListElem *rule - Current rule
 
278
*     sge_assignment_t *a   - Assignment
 
279
*
 
280
*  RESULT
 
281
*     static bool - True if shadowed
 
282
*
 
283
*  EXAMPLE
 
284
*     limits hosts host1,host2 to F001=1
 
285
*     limits hosts host2,host3 to F001=1 (--> returns 'true' for host2 and 'false' for host3)
 
286
*
 
287
*  NOTES
 
288
*     MT-NOTE: host_shadowed_by() is MT safe
 
289
*******************************************************************************/
 
290
static bool host_shadowed_by(const char *host, const lListElem *rule, sge_assignment_t *a)
 
291
{
 
292
   while ((rule = lPrev(rule))) {
 
293
      if (rqs_match_assignment(rule, a) &&
 
294
          rqs_filter_match(lGetObject(rule, RQR_filter_hosts), FILTER_HOSTS, host, NULL, a->hgrp_list, NULL)) {
 
295
         return true;
 
296
      }
 
297
   }
 
298
 
 
299
   return false;
 
300
}
 
301
 
 
302
/****** sge_resource_quota_schedd/rqs_can_optimize() ***************************
 
303
*  NAME
 
304
*     rqs_can_optimize() -- Poke whether a queue/host negation can be made
 
305
*
 
306
*  SYNOPSIS
 
307
*     static void rqs_can_optimize(const lListElem *rule, bool *host, bool
 
308
*     *queue, sge_assignment_t *a)
 
309
*
 
310
*  FUNCTION
 
311
*     A global limit was hit with 'rule'. This function helps to determine
 
312
*     to what exend we can profit from that situation. If there is no
 
313
*     previous matching rule within the same rule set any other queue/host
 
314
*     can be skipped.
 
315
*
 
316
*  INPUTS
 
317
*     const lListElem *rule - Rule
 
318
*     bool *host            - Any previous rule with a host scope?
 
319
*     bool *queue           - Any previous rule with a queue scope?
 
320
*     sge_assignment_t *a   - Scheduler assignment
 
321
*
 
322
*  NOTES
 
323
*     MT-NOTE: rqs_can_optimize() is MT safe
 
324
*******************************************************************************/
 
325
static void rqs_can_optimize(const lListElem *rule, bool *host, bool *queue, sge_assignment_t *a)
 
326
{
 
327
   bool host_shadowed = false, queue_shadowed = false;
 
328
 
 
329
   const lListElem *prev = rule;
 
330
   while ((prev = lPrev(prev))) {
 
331
      if (!rqs_match_assignment(rule, a))
 
332
         continue;
 
333
      if (!is_host_global(prev))
 
334
         host_shadowed = true;
 
335
      if (!is_cqueue_global(prev))
 
336
         queue_shadowed = true;
 
337
   }
 
338
 
 
339
   *host = host_shadowed;
 
340
   *queue = queue_shadowed;
 
341
 
 
342
   return;
 
343
}
 
344
 
 
345
/****** sge_resource_quota_schedd/rqs_excluded_cqueues() ***********************
 
346
*  NAME
 
347
*     rqs_excluded_cqueues() -- Find excluded queues
 
348
*
 
349
*  SYNOPSIS
 
350
*     static void rqs_excluded_cqueues(const lListElem *rule, sge_assignment_t *a)
 
351
*
 
352
*  FUNCTION
 
353
*     Find queues that are excluded by previous rules.
 
354
*
 
355
*  INPUTS
 
356
*     const lListElem *rule    - The rule
 
357
*     sge_assignment_t *a      - Scheduler assignement
 
358
*
 
359
*  EXAMPLE
 
360
*      limit        projects {*} queues !Q001 to F001=1
 
361
*      limit        to F001=0   ( ---> returns Q001 in a->skip_cqueue_list)
 
362
*
 
363
*  NOTES
 
364
*     MT-NOTE: rqs_excluded_cqueues() is MT safe
 
365
*******************************************************************************/
 
366
static void rqs_excluded_cqueues(const lListElem *rule, sge_assignment_t *a)
 
367
{
 
368
   lListElem *cq;
 
369
   const lListElem *prev;
 
370
   int ignored = 0, excluded = 0;
 
371
 
 
372
   DENTER(TOP_LAYER, "rqs_excluded_cqueues");
 
373
 
 
374
   for_each (cq, *(object_type_get_master_list(SGE_TYPE_CQUEUE))) {
 
375
      const char *cqname = lGetString(cq, CQ_name);
 
376
      bool exclude = true;
 
377
 
 
378
      if (lGetElemStr(a->skip_cqueue_list, CTI_name, cqname)) {
 
379
         ignored++;
 
380
         continue;
 
381
      }
 
382
 
 
383
      prev = rule;
 
384
      while ((prev = lPrev(prev))) {
 
385
         if (!rqs_match_assignment(rule, a))
 
386
            continue;
 
387
 
 
388
         if (rqs_filter_match(lGetObject(prev, RQR_filter_queues), FILTER_QUEUES, cqname, NULL, NULL, NULL)) {
 
389
            exclude = false;
 
390
            break;
 
391
         }
 
392
      }
 
393
      if (exclude) {
 
394
         lAddElemStr(&(a->skip_cqueue_list), CTI_name, cqname, CTI_Type);
 
395
         excluded++;
 
396
      }
 
397
   }
 
398
 
 
399
   if (ignored + excluded == 0) {
 
400
      CRITICAL((SGE_EVENT, "not a single queue excluded in rqs_excluded_cqueues()\n"));
 
401
   }
 
402
 
 
403
   DRETURN_VOID;
 
404
}
 
405
 
 
406
/****** sge_resource_quota_schedd/rqs_excluded_hosts() *************************
 
407
*  NAME
 
408
*     rqs_excluded_hosts() -- Find excluded hosts
 
409
*
 
410
*  SYNOPSIS
 
411
*     static void rqs_excluded_hosts(const lListElem *rule, sge_assignment_t *a)
 
412
*
 
413
*  FUNCTION
 
414
*     Find hosts that are excluded by previous rules.
 
415
*
 
416
*  INPUTS
 
417
*     const lListElem *rule    - The rule
 
418
*     sge_assignment_t *a      - Scheduler assignement
 
419
*
 
420
*  EXAMPLE
 
421
*      limit        projects {*} queues !gridware to F001=1
 
422
*      limit        to F001=0   ( ---> returns gridware in skip_host_list)
 
423
*
 
424
*  NOTES
 
425
*     MT-NOTE: rqs_excluded_hosts() is MT safe
 
426
*******************************************************************************/
 
427
static void rqs_excluded_hosts(const lListElem *rule, sge_assignment_t *a)
 
428
{
 
429
   lListElem *eh;
 
430
   const lListElem *prev;
 
431
   int ignored = 0, excluded = 0;
 
432
 
 
433
   DENTER(TOP_LAYER, "rqs_excluded_hosts");
 
434
 
 
435
   for_each (eh, a->host_list) {
 
436
      const char *hname = lGetHost(eh, EH_name);
 
437
      bool exclude = true;
 
438
 
 
439
      if (lGetElemStr(a->skip_host_list, CTI_name, hname)) {
 
440
         ignored++;
 
441
         continue;
 
442
      }
 
443
 
 
444
      prev = rule;
 
445
      while ((prev = lPrev(prev))) {
 
446
         if (!rqs_match_assignment(rule, a))
 
447
            continue;
 
448
 
 
449
         if (rqs_filter_match(lGetObject(prev, RQR_filter_hosts), FILTER_HOSTS, hname, NULL, a->hgrp_list, NULL)) {
 
450
            exclude = false;
 
451
            break;
 
452
         }
 
453
      }
 
454
      if (exclude) {
 
455
         lAddElemStr(&(a->skip_host_list), CTI_name, hname, CTI_Type);
 
456
         excluded++;
 
457
      }
 
458
   }
 
459
 
 
460
   if (ignored + excluded == 0) {
 
461
      CRITICAL((SGE_EVENT, "not a single host excluded in rqs_excluded_hosts()\n"));
 
462
   }
 
463
 
 
464
   DRETURN_VOID;
 
465
}
 
466
 
 
467
/****** sge_resource_quota_schedd/rqs_expand_cqueues() *************************
 
468
*  NAME
 
469
*     rqs_expand_cqueues() -- Add all matching cqueues to the list
 
470
*
 
471
*  SYNOPSIS
 
472
*     void rqs_expand_cqueues(const lListElem *rule)
 
473
*
 
474
*  FUNCTION
 
475
*     The names of all cluster queues that match the rule are added to
 
476
*     the skip list without duplicates.
 
477
*
 
478
*  INPUTS
 
479
*     const lListElem *rule    - RQR_Type
 
480
*
 
481
*  NOTES
 
482
*     MT-NOTE: rqs_expand_cqueues() is not MT safe
 
483
*******************************************************************************/
 
484
static void rqs_expand_cqueues(const lListElem *rule, sge_assignment_t *a)
 
485
{
 
486
   const lListElem *cq;
 
487
   const char *cqname;
 
488
   lListElem *qfilter = lGetObject(rule, RQR_filter_queues);
 
489
 
 
490
   DENTER(TOP_LAYER, "rqs_expand_cqueues");
 
491
 
 
492
   for_each (cq, *(object_type_get_master_list(SGE_TYPE_CQUEUE))) {
 
493
      cqname = lGetString(cq, CQ_name);
 
494
      if (lGetElemStr(a->skip_cqueue_list, CTI_name, cqname))
 
495
         continue;
 
496
      if (rqs_filter_match(qfilter, FILTER_QUEUES, cqname, NULL, NULL, NULL) && !cqueue_shadowed_by(cqname, rule, a))
 
497
         lAddElemStr(&(a->skip_cqueue_list), CTI_name, cqname, CTI_Type);
 
498
   }
 
499
 
 
500
   DEXIT;
 
501
   return;
 
502
}
 
503
 
 
504
/****** sge_resource_quota_schedd/rqs_expand_hosts() ***************************
 
505
*  NAME
 
506
*     rqs_expand_hosts() -- Add all matching hosts to the list
 
507
*
 
508
*  SYNOPSIS
 
509
*     void rqs_expand_hosts(const lListElem *rule, lList **skip_host_list,
 
510
*     const lList *host_list, lList *hgrp_list)
 
511
*
 
512
*  FUNCTION
 
513
*     The names of all hosts that match the rule are added to
 
514
*     the skip list without duplicates.
 
515
*
 
516
*  INPUTS
 
517
*     const lListElem *rule  - RQR_Type
 
518
*     const lList *host_list - EH_Type
 
519
*
 
520
*  NOTES
 
521
*     MT-NOTE: rqs_expand_hosts() is MT safe
 
522
*******************************************************************************/
 
523
static void rqs_expand_hosts(const lListElem *rule, sge_assignment_t *a)
 
524
{
 
525
   const lListElem *eh;
 
526
   const char *hname;
 
527
   lListElem *hfilter = lGetObject(rule, RQR_filter_hosts);
 
528
 
 
529
   for_each (eh, a->host_list) {
 
530
      hname = lGetHost(eh, EH_name);
 
531
      if (lGetElemStr(a->skip_host_list, CTI_name, hname))
 
532
         continue;
 
533
      if (rqs_filter_match(hfilter, FILTER_HOSTS, hname, NULL, a->hgrp_list, NULL) && !host_shadowed_by(hname, rule, a))
 
534
         lAddElemStr(&(a->skip_host_list), CTI_name, hname, CTI_Type);
 
535
   }
 
536
 
 
537
   return;
 
538
}
 
539
 
 
540
static bool is_global(const lListElem *rule, int nm)
 
541
{
 
542
   lListElem *filter = lGetObject(rule, nm);
 
543
   if (!filter)
 
544
      return true;
 
545
   if (lGetSubStr(filter, ST_name, "*", RQRF_scope) && lGetNumberOfElem(lGetList(filter, RQRF_xscope))==0)
 
546
      return true;
 
547
   return false;
 
548
}
 
549
 
 
550
/****** sge_resource_quota_schedd/is_cqueue_global() ***************************
 
551
*  NAME
 
552
*     is_cqueue_global() -- Global rule with regards to cluster queues?
 
553
*
 
554
*  SYNOPSIS
 
555
*     bool is_cqueue_global(const lListElem *rule)
 
556
*
 
557
*  INPUTS
 
558
*     const lListElem *rule - RQR_Type
 
559
*
 
560
*  RESULT
 
561
*     bool - True if cluster queues play no role with the rule
 
562
*
 
563
*  NOTES
 
564
*     MT-NOTE: is_cqueue_global() is MT safe
 
565
*******************************************************************************/
 
566
static bool is_cqueue_global(const lListElem *rule)
 
567
{
 
568
   return is_global(rule, RQR_filter_queues);
 
569
}
 
570
 
 
571
 
 
572
/****** sge_resource_quota_schedd/is_host_global() *****************************
 
573
*  NAME
 
574
*     is_host_global() -- Global rule with regards to hosts?
 
575
*
 
576
*  SYNOPSIS
 
577
*     bool is_host_global(const lListElem *rule)
 
578
*
 
579
*  FUNCTION
 
580
*     Return true if hosts play no role with the rule
 
581
*
 
582
*  INPUTS
 
583
*     const lListElem *rule - RQR_Type
 
584
*
 
585
*  RESULT
 
586
*     bool - True if hosts play no role with the rule
 
587
*
 
588
*  NOTES
 
589
*     MT-NOTE: is_host_global() is MT safe
 
590
*******************************************************************************/
 
591
static bool is_host_global(const lListElem *rule)
 
592
{
 
593
   return is_global(rule, RQR_filter_hosts);
 
594
}
 
595
 
 
596
static bool is_expand(const lListElem *rule, int nm)
 
597
{
 
598
   lListElem *filter = lGetObject(rule, nm);
 
599
   if (filter && lGetBool(filter, RQRF_expand) == true)
 
600
      return true;
 
601
   else
 
602
      return false;
 
603
}
 
604
 
 
605
 
 
606
/****** sge_resource_quota_schedd/is_host_expand() *****************************
 
607
*  NAME
 
608
*     is_host_expand() -- Returns true if rule expands on hosts
 
609
*
 
610
*  SYNOPSIS
 
611
*     bool is_host_expand(const lListElem *rule)
 
612
*
 
613
*  FUNCTION
 
614
*     Returns true if rule expands on hosts.
 
615
*
 
616
*  INPUTS
 
617
*     const lListElem *rule - RQR_Type
 
618
*
 
619
*  RESULT
 
620
*     bool - True if rule expands on hosts
 
621
*
 
622
*  EXAMPLE
 
623
*      "hosts {*}" returns true
 
624
*      "hosts @allhosts" returns false
 
625
*
 
626
*  NOTES
 
627
*     MT-NOTE: is_host_expand() is MT safe
 
628
*******************************************************************************/
 
629
static bool is_host_expand(const lListElem *rule)
 
630
{
 
631
   return is_expand(rule, RQR_filter_hosts);
 
632
}
 
633
 
 
634
/****** sge_resource_quota_schedd/is_cqueue_expand() ***************************
 
635
*  NAME
 
636
*     is_cqueue_expand() -- Returns true if rule expands on cluster queues
 
637
*
 
638
*  SYNOPSIS
 
639
*     bool is_cqueue_expand(const lListElem *rule)
 
640
*
 
641
*  FUNCTION
 
642
*     Returns true if rule expands on cluster queues.
 
643
*
 
644
*  INPUTS
 
645
*     const lListElem *rule - RQR_Type
 
646
*
 
647
*  RESULT
 
648
*     bool - True if rule expands on hosts
 
649
*
 
650
*  EXAMPLE
 
651
*      "queues {*}" returns true
 
652
*      "queues Q001,Q002" returns false
 
653
*
 
654
*  NOTES
 
655
*     MT-NOTE: is_cqueue_expand() is MT safe
 
656
*******************************************************************************/
 
657
static bool is_cqueue_expand(const lListElem *rule)
 
658
{
 
659
   return is_expand(rule, RQR_filter_queues);
 
660
}
 
661
 
 
662
/****** sge_resource_quota_schedd/rqs_exceeded_sort_out() **********************
 
663
*  NAME
 
664
*     rqs_exceeded_sort_out() -- Rule out queues/hosts whenever possible
 
665
*
 
666
*  SYNOPSIS
 
667
*     bool rqs_exceeded_sort_out(sge_assignment_t *a, const lListElem *rule,
 
668
*     const dstring *rule_name, const char* queue_name, const char* host_name)
 
669
*
 
670
*  FUNCTION
 
671
*     This function tries to rule out hosts and cluster queues after a
 
672
*     quota exeeding was found for a limitation rule with specific queue
 
673
*     instance.
 
674
*
 
675
*     When a limitation was exeeded that applies to the entire
 
676
*     cluster 'true' is returned, 'false' otherwise.
 
677
*
 
678
*  INPUTS
 
679
*     sge_assignment_t *a      - Scheduler assignment type
 
680
*     const lListElem *rule    - The exeeded rule
 
681
*     const dstring *rule_name - Name of the rule (monitoring only)
 
682
*     const char* queue_name   - Cluster queue name
 
683
*     const char* host_name    - Host name
 
684
*
 
685
*  RESULT
 
686
*     bool - True upon global limits exceeding
 
687
*
 
688
*  NOTES
 
689
*     MT-NOTE: rqs_exceeded_sort_out() is MT safe
 
690
*******************************************************************************/
 
691
static bool rqs_exceeded_sort_out(sge_assignment_t *a, const lListElem *rule, const dstring *rule_name,
 
692
   const char* queue_name, const char* host_name)
 
693
{
 
694
   bool cq_global = is_cqueue_global(rule);
 
695
   bool eh_global = is_host_global(rule);
 
696
 
 
697
   DENTER(TOP_LAYER, "rqs_exceeded_sort_out");
 
698
 
 
699
   if ((!cq_global && !eh_global) || (cq_global && eh_global &&
 
700
         (is_cqueue_expand(rule) || is_host_expand(rule)))) { /* failure at queue instance limit */
 
701
      DPRINTF(("QUEUE INSTANCE: resource quota set %s deny job execution on %s@%s\n", 
 
702
            sge_dstring_get_string(rule_name), queue_name, host_name));
 
703
      DRETURN(false);
 
704
   }
 
705
 
 
706
   if (cq_global && eh_global) { /* failure at a global limit */
 
707
      bool host_shadowed, queue_shadowed;
 
708
 
 
709
      rqs_can_optimize(rule, &host_shadowed, &queue_shadowed, a);
 
710
      if (!host_shadowed && !queue_shadowed) {
 
711
         DPRINTF(("GLOBAL: resource quota set %s deny job execution globally\n", 
 
712
               sge_dstring_get_string(rule_name)));
 
713
         DRETURN(true);
 
714
      }
 
715
 
 
716
      if (host_shadowed && queue_shadowed) {
 
717
         rqs_excluded_cqueues(rule, a);
 
718
         rqs_excluded_hosts(rule, a);
 
719
         DPRINTF(("QUEUE INSTANCE: resource quota set %s deny job execution on %s@%s\n", 
 
720
               sge_dstring_get_string(rule_name), queue_name, host_name));
 
721
         DRETURN(false);
 
722
      }
 
723
 
 
724
      if (queue_shadowed) {
 
725
         rqs_excluded_cqueues(rule, a);
 
726
         DPRINTF(("QUEUE: resource quota set %s deny job execution in all its queues\n", 
 
727
               sge_dstring_get_string(rule_name)));
 
728
      } else { /* must be host_shadowed */
 
729
         rqs_excluded_hosts(rule, a);
 
730
         DPRINTF(("HOST: resource quota set %s deny job execution in all its queues\n", 
 
731
               sge_dstring_get_string(rule_name)));
 
732
      }
 
733
 
 
734
      DRETURN(false);
 
735
   }
 
736
 
 
737
   if (!cq_global) { /* failure at a cluster queue limit */
 
738
 
 
739
      if (host_shadowed(rule, a)) {
 
740
         DPRINTF(("QUEUE INSTANCE: resource quota set %s deny job execution on %s@%s\n", 
 
741
               sge_dstring_get_string(rule_name), queue_name, host_name));
 
742
         DRETURN(false);
 
743
      }
 
744
 
 
745
      if (lGetBool(lGetObject(rule, RQR_filter_queues), RQRF_expand) == true) {
 
746
         lAddElemStr(&(a->skip_cqueue_list), CTI_name, queue_name, CTI_Type);
 
747
         DPRINTF(("QUEUE: resource quota set %s deny job execution in queue %s\n", 
 
748
               sge_dstring_get_string(rule_name), queue_name));
 
749
      } else {
 
750
         rqs_expand_cqueues(rule, a);
 
751
         DPRINTF(("QUEUE: resource quota set %s deny job execution in all its queues\n", 
 
752
               sge_dstring_get_string(rule_name)));
 
753
      }
 
754
 
 
755
      DRETURN(false);
 
756
   }
 
757
 
 
758
   /* must be (!eh_global) */
 
759
   { /* failure at a host limit */
 
760
 
 
761
      if (cqueue_shadowed(rule, a)) {
 
762
         DPRINTF(("QUEUE INSTANCE: resource quota set %s deny job execution on %s@%s\n", 
 
763
               sge_dstring_get_string(rule_name), queue_name, host_name));
 
764
         DRETURN(false);
 
765
      }
 
766
 
 
767
      if (lGetBool(lGetObject(rule, RQR_filter_hosts), RQRF_expand) == true) {
 
768
         lAddElemStr(&(a->skip_host_list), CTI_name, host_name, CTI_Type);
 
769
         DPRINTF(("HOST: resource quota set %s deny job execution at host %s\n",    
 
770
               sge_dstring_get_string(rule_name), host_name));
 
771
      } else {
 
772
         rqs_expand_hosts(rule, a);
 
773
         DPRINTF(("HOST: resource quota set %s deny job execution at all its hosts\n", 
 
774
               sge_dstring_get_string(rule_name)));
 
775
      }
 
776
 
 
777
      DRETURN(false);
 
778
   }
 
779
}
 
780
 
 
781
/****** sge_resource_quota_schedd/rqs_exceeded_sort_out_par() ******************
 
782
*  NAME
 
783
*     rqs_exceeded_sort_out_par() -- Rule out queues/hosts whenever possible
 
784
*
 
785
*  SYNOPSIS
 
786
*     void rqs_exceeded_sort_out_par(sge_assignment_t *a, const lListElem 
 
787
*     *rule, const dstring *rule_name, const char* queue_name, const char* 
 
788
*     host_name) 
 
789
*
 
790
*  FUNCTION
 
791
*     Function wrapper around rqs_exceeded_sort_out() for parallel jobs.
 
792
*     In contrast to the sequential case global limit exeeding is handled
 
793
*     by adding all cluster queue names to the a->skip_cqueue_list.
 
794
*
 
795
*  INPUTS
 
796
*     sge_assignment_t *a      - Scheduler assignment type
 
797
*     const lListElem *rule    - The exeeded rule
 
798
*     const dstring *rule_name - Name of the rule (monitoring only)
 
799
*     const char* queue_name   - Cluster queue name
 
800
*     const char* host_name    - Host name
 
801
*
 
802
*  NOTES
 
803
*     MT-NOTE: rqs_exceeded_sort_out_par() is MT safe 
 
804
*******************************************************************************/
 
805
static void rqs_exceeded_sort_out_par(sge_assignment_t *a, const lListElem *rule, const dstring *rule_name,
 
806
   const char* queue_name, const char* host_name)
 
807
{
 
808
   if (rqs_exceeded_sort_out(a, rule, rule_name, queue_name, host_name)) {
 
809
      rqs_expand_hosts(rule, a);
 
810
   }
 
811
}
 
812
 
 
813
/****** sge_resource_quota_schedd/sge_user_is_referenced_in_rqs() ********************
 
814
*  NAME
 
815
*     sge_user_is_referenced_in_rqs() -- search for user reference in rqs 
 
816
*
 
817
*  SYNOPSIS
 
818
*     bool sge_user_is_referenced_in_rqs(const lList *rqs, const char *user, 
 
819
*     lList *acl_list) 
 
820
*
 
821
*  FUNCTION
 
822
*     Search for a user reference in the resource quota sets
 
823
*
 
824
*  INPUTS
 
825
*     const lList *rqs - resource quota set list
 
826
*     const char *user  - user to search
 
827
*     const char *group - user's group
 
828
*     lList *acl_list   - acl list for user resolving
 
829
*
 
830
*  RESULT
 
831
*     bool - true if user was found
 
832
*            false if user was not found
 
833
*
 
834
*  NOTES
 
835
*     MT-NOTE: sge_user_is_referenced_in_rqs() is MT safe 
 
836
*
 
837
*******************************************************************************/
 
838
bool sge_user_is_referenced_in_rqs(const lList *rqs, const char *user, const char *group, lList *acl_list)
 
839
{
 
840
   bool ret = false;
 
841
   lListElem *ep;
 
842
 
 
843
   for_each(ep, rqs) {
 
844
      lList *rule_list = lGetList(ep, RQS_rule);
 
845
      lListElem *rule;
 
846
      for_each(rule, rule_list) {
 
847
         /* there may be no per-user limitation and also not limitation that is special for this user */
 
848
         if ((is_expand(rule, RQR_filter_users) || !is_global(rule, RQR_filter_users)) &&
 
849
             rqs_filter_match(lGetObject(rule, RQR_filter_users), FILTER_USERS, user,
 
850
             acl_list, NULL, group)) {
 
851
            ret = true;
 
852
            break;
 
853
         }
 
854
      }
 
855
      if (ret == true) {
 
856
         break;
 
857
      }
 
858
   }
 
859
   return ret;
 
860
}
 
861
 
 
862
 
 
863
/****** sge_resource_quota_schedd/check_and_debit_rqs_slots() *********************
 
864
*  NAME
 
865
*     check_and_debit_rqs_slots() -- Determine RQS limit slot amount and debit
 
866
*
 
867
*  SYNOPSIS
 
868
*     static void check_and_debit_rqs_slots(sge_assignment_t *a, const char 
 
869
*     *host, const char *queue, int *slots, int *slots_qend, dstring 
 
870
*     *rule_name, dstring *rue_name, dstring *limit_name) 
 
871
*
 
872
*  FUNCTION
 
873
*     The function determines the final slot and slots_qend amount due
 
874
*     to all resource quota limitations that apply for the queue instance. 
 
875
*     Both slot amounts get debited from the a->limit_list to keep track 
 
876
*     of still available amounts per resource quota limit.
 
877
*
 
878
*  INPUTS
 
879
*     sge_assignment_t *a - Assignment data structure
 
880
*     const char *host    - hostname
 
881
*     const char *queue   - queuename
 
882
*     int *slots          - needed/available slots
 
883
*     int *slots_qend     - needed/available slots_qend
 
884
*     dstring *rule_name  - caller maintained buffer
 
885
*     dstring *rue_name   - caller maintained buffer
 
886
*     dstring *limit_name - caller maintained buffer
 
887
*
 
888
*  NOTES
 
889
*     MT-NOTE: check_and_debit_rqs_slots() is MT safe 
 
890
*******************************************************************************/
 
891
void parallel_check_and_debit_rqs_slots(sge_assignment_t *a, const char *host, const char *queue, 
 
892
      int *slots, int *slots_qend, dstring *rule_name, dstring *rue_name, dstring *limit_name)
 
893
{
 
894
   lListElem *rqs, *rule;
 
895
   const char* user = a->user;
 
896
   const char* group = a->group;
 
897
   const char* project = a->project;
 
898
   const char* pe = a->pe_name;
 
899
 
 
900
   DENTER(TOP_LAYER, "parallel_check_and_debit_rqs_slots");
 
901
 
 
902
   /* first step - see how many slots are left */
 
903
   for_each(rqs, a->rqs_list) {
 
904
 
 
905
      /* ignore disabled rule sets */
 
906
      if (!lGetBool(rqs, RQS_enabled)) {
 
907
         continue;
 
908
      }
 
909
      sge_dstring_clear(rule_name);
 
910
      rule = rqs_get_matching_rule(rqs, user, group, project, pe, host, queue, a->acl_list, a->hgrp_list, rule_name);
 
911
      if (rule != NULL) {
 
912
         lListElem *rql;
 
913
         rqs_get_rue_string(rue_name, rule, user, project, host, queue, pe);
 
914
         sge_dstring_sprintf(limit_name, "%s=%s", sge_dstring_get_string(rule_name), sge_dstring_get_string(rue_name));
 
915
         if ((rql = lGetElemStr(a->limit_list, RQL_name, sge_dstring_get_string(limit_name)))) {
 
916
            *slots = MIN(*slots, lGetInt(rql, RQL_slots));
 
917
            *slots_qend = MIN(*slots_qend, lGetInt(rql, RQL_slots_qend));
 
918
         } else {
 
919
            *slots = *slots_qend = 0;
 
920
         }
 
921
      }
 
922
 
 
923
      if (*slots == 0 && *slots_qend == 0) {
 
924
         break;
 
925
      }
 
926
   }
 
927
 
 
928
   /* second step - reduce number of remaining slots  */
 
929
   if (*slots != 0 || *slots_qend != 0) {
 
930
      for_each(rqs, a->rqs_list) {
 
931
 
 
932
         /* ignore disabled rule sets */
 
933
         if (!lGetBool(rqs, RQS_enabled)) {
 
934
            continue;
 
935
         }
 
936
         sge_dstring_clear(rule_name);
 
937
         rule = rqs_get_matching_rule(rqs, user, group, project, pe, host, queue, a->acl_list, a->hgrp_list, rule_name);
 
938
         if (rule != NULL) {
 
939
            lListElem *rql;
 
940
            rqs_get_rue_string(rue_name, rule, user, project, host, queue, pe);
 
941
            sge_dstring_sprintf(limit_name, "%s=%s", sge_dstring_get_string(rule_name), sge_dstring_get_string(rue_name));
 
942
            rql = lGetElemStr(a->limit_list, RQL_name, sge_dstring_get_string(limit_name));
 
943
            lSetInt(rql, RQL_slots,      lGetInt(rql, RQL_slots) - *slots);
 
944
            lSetInt(rql, RQL_slots_qend, lGetInt(rql, RQL_slots_qend) - *slots_qend);
 
945
         }
 
946
      }
 
947
   }
 
948
 
 
949
   DPRINTF(("check_and_debit_rqs_slots(%s@%s) slots: %d slots_qend: %d\n", queue, host, *slots, *slots_qend));
 
950
 
 
951
   DRETURN_VOID;
 
952
}
 
953
 
 
954
void parallel_revert_rqs_slot_debitation(sge_assignment_t *a, const char *host, const char *queue, 
 
955
      int slots, int slots_qend, dstring *rule_name, dstring *rue_name, dstring *limit_name)
 
956
{
 
957
   lListElem *rqs, *rule;
 
958
   const char* user = a->user;
 
959
   const char* group = a->group;
 
960
   const char* project = a->project;
 
961
   const char* pe = a->pe_name;
 
962
 
 
963
   DENTER(TOP_LAYER, "parallel_check_and_debit_rqs_slots");
 
964
 
 
965
   for_each(rqs, a->rqs_list) {
 
966
 
 
967
      /* ignore disabled rule sets */
 
968
      if (!lGetBool(rqs, RQS_enabled)) {
 
969
         continue;
 
970
      }
 
971
      sge_dstring_clear(rule_name);
 
972
      rule = rqs_get_matching_rule(rqs, user, group, project, pe, host, queue, a->acl_list, a->hgrp_list, rule_name);
 
973
      if (rule != NULL) {
 
974
         lListElem *rql;
 
975
         rqs_get_rue_string(rue_name, rule, user, project, host, queue, pe);
 
976
         sge_dstring_sprintf(limit_name, "%s=%s", sge_dstring_get_string(rule_name), sge_dstring_get_string(rue_name));
 
977
         rql = lGetElemStr(a->limit_list, RQL_name, sge_dstring_get_string(limit_name));
 
978
         DPRINTF(("limit: %s %d <--- %d\n", sge_dstring_get_string(limit_name), 
 
979
               lGetInt(rql, RQL_slots), lGetInt(rql, RQL_slots)+slots));
 
980
         lSetInt(rql, RQL_slots,      lGetInt(rql, RQL_slots) + slots);
 
981
         lSetInt(rql, RQL_slots_qend, lGetInt(rql, RQL_slots_qend) + slots_qend);
 
982
      }
 
983
   }
 
984
 
 
985
   DRETURN_VOID;
 
986
}
 
987
 
 
988
/****** sge_resource_quota_schedd/parallel_limit_slots_by_time() ********************
 
989
*  NAME
 
990
*     parallel_limit_slots_by_time() -- Determine number of slots avail. within
 
991
*                                       time frame
 
992
*
 
993
*  SYNOPSIS
 
994
*     static dispatch_t parallel_limit_slots_by_time(const sge_assignment_t *a, 
 
995
*     lList *requests, int *slots, int *slots_qend, lListElem *centry, lListElem 
 
996
*     *limit, dstring rue_name) 
 
997
*
 
998
*  FUNCTION
 
999
*     ??? 
 
1000
*
 
1001
*  INPUTS
 
1002
*     const sge_assignment_t *a - job info structure (in)
 
1003
*     lList *requests           - Job request list (CE_Type)
 
1004
*     int *slots                - out: free slots
 
1005
*     int *slots_qend           - out: free slots in the far far future
 
1006
*     lListElem *centry         - Load information for the resource
 
1007
*     lListElem *limit          - limitation (RQRL_Type)
 
1008
*     dstring rue_name          - rue_name saved in limit sublist RQRL_usage
 
1009
*
 
1010
*  RESULT
 
1011
*     static dispatch_t - DISPATCH_OK        got an assignment
 
1012
*                       - DISPATCH_NEVER_CAT no assignment for all jobs af that category
 
1013
*
 
1014
*  NOTES
 
1015
*     MT-NOTE: parallel_limit_slots_by_time() is not MT safe 
 
1016
*
 
1017
*  SEE ALSO
 
1018
*     parallel_rc_slots_by_time
 
1019
*******************************************************************************/
 
1020
static dispatch_t 
 
1021
parallel_limit_slots_by_time(const sge_assignment_t *a, lList *requests, 
 
1022
                 int *slots, int *slots_qend, lListElem *centry, lListElem *limit, dstring *rue_name)
 
1023
{
 
1024
   lList *tmp_centry_list = lCreateList("", CE_Type);
 
1025
   lList *tmp_rue_list = lCreateList("", RUE_Type);
 
1026
   lListElem *tmp_centry_elem = NULL;
 
1027
   lListElem *tmp_rue_elem = NULL;
 
1028
   lList *rue_list = lGetList(limit, RQRL_usage);
 
1029
   dispatch_t result = DISPATCH_NEVER_CAT;
 
1030
 
 
1031
   DENTER(TOP_LAYER, "parallel_limit_slots_by_time");
 
1032
 
 
1033
   /* create tmp_centry_list */
 
1034
   tmp_centry_elem = lCopyElem(centry);
 
1035
   lSetDouble(tmp_centry_elem, CE_doubleval, lGetDouble(limit, RQRL_dvalue));
 
1036
   lAppendElem(tmp_centry_list, tmp_centry_elem);
 
1037
 
 
1038
   /* create tmp_rue_list */
 
1039
   tmp_rue_elem = lCopyElem(lGetElemStr(rue_list, RUE_name, sge_dstring_get_string(rue_name)));
 
1040
   if (tmp_rue_elem == NULL) {
 
1041
      tmp_rue_elem = lCreateElem(RUE_Type);
 
1042
   }
 
1043
 
 
1044
   lSetString(tmp_rue_elem, RUE_name, lGetString(limit, RQRL_name));
 
1045
   lAppendElem(tmp_rue_list, tmp_rue_elem);
 
1046
 
 
1047
   result = parallel_rc_slots_by_time(a, requests, slots, 
 
1048
                                      slots_qend, tmp_centry_list, tmp_rue_list, NULL,  
 
1049
                                      false, NULL, DOMINANT_LAYER_RQS, 0.0, RQS_TAG,
 
1050
                                      false, SGE_RQS_NAME, true);
 
1051
   
 
1052
   lFreeList(&tmp_centry_list);
 
1053
   lFreeList(&tmp_rue_list);
 
1054
 
 
1055
   DRETURN(result);
 
1056
}
 
1057
 
 
1058
 
 
1059
/****** sge_resource_quota_schedd/parallel_rqs_slots_by_time() ******************
 
1060
*  NAME
 
1061
*     parallel_rqs_slots_by_time() -- Dertermine number of slots avail within
 
1062
*                                      time frame
 
1063
*
 
1064
*  SYNOPSIS
 
1065
*     dispatch_t parallel_rqs_slots_by_time(const sge_assignment_t *a, 
 
1066
*     int *slots, int *slots_qend, const char *host, const char *queue) 
 
1067
*
 
1068
*  FUNCTION
 
1069
*     This function iterates for a queue instance over all resource quota sets
 
1070
*     and evaluates the number of slots available.
 
1071
*
 
1072
*  INPUTS
 
1073
*     const sge_assignment_t *a - job info structure (in)
 
1074
*     int *slots                - out: # free slots
 
1075
*     int *slots_qend           - out: # free slots in the far far future
 
1076
*     const char *host          - host name
 
1077
*     const char *queue         - queue name
 
1078
*
 
1079
*  RESULT
 
1080
*     static dispatch_t - DISPATCH_OK        got an assignment
 
1081
*                       - DISPATCH_NEVER_CAT no assignment for all jobs af that category
 
1082
*
 
1083
*  NOTES
 
1084
*     MT-NOTE: parallel_rqs_slots_by_time() is not MT safe 
 
1085
*
 
1086
*  SEE ALSO
 
1087
*     ri_slots_by_time()
 
1088
*     
 
1089
*******************************************************************************/
 
1090
dispatch_t
 
1091
parallel_rqs_slots_by_time(sge_assignment_t *a, int *slots, int *slots_qend, const char *host, const char *queue)
 
1092
{
 
1093
   dispatch_t result = DISPATCH_OK;
 
1094
   int tslots = INT_MAX;
 
1095
   int tslots_qend = INT_MAX;
 
1096
 
 
1097
   DENTER(TOP_LAYER, "parallel_rqs_slots_by_time");
 
1098
 
 
1099
   if (lGetNumberOfElem(a->rqs_list) != 0) {
 
1100
      const char* user = a->user;
 
1101
      const char* group = a->group;
 
1102
      const char* project = a->project;
 
1103
      const char* pe = a->pe_name;
 
1104
      lListElem *rql, *rqs;
 
1105
      dstring rule_name = DSTRING_INIT;
 
1106
      dstring rue_string = DSTRING_INIT;
 
1107
      dstring limit_name = DSTRING_INIT;
 
1108
 
 
1109
      if (a->pi)
 
1110
         a->pi->par_rqs++;
 
1111
 
 
1112
      for_each(rqs, a->rqs_list) {
 
1113
         lListElem *rule = NULL;
 
1114
         lListElem *exec_host = host_list_locate(a->host_list, host);
 
1115
 
 
1116
         /* ignore disabled rule sets */
 
1117
         if (!lGetBool(rqs, RQS_enabled)) {
 
1118
            continue;
 
1119
         }
 
1120
         sge_dstring_clear(&rule_name);
 
1121
         rule = rqs_get_matching_rule(rqs, user, group, project, pe, host, queue, a->acl_list, a->hgrp_list, &rule_name);
 
1122
         if (rule != NULL) {
 
1123
            lListElem *limit = NULL;
 
1124
            const char *limit_s;
 
1125
            rqs_get_rue_string(&rue_string, rule, user, project, host, queue, pe);
 
1126
            sge_dstring_sprintf(&limit_name, "%s=%s", sge_dstring_get_string(&rule_name), sge_dstring_get_string(&rue_string));
 
1127
            limit_s = sge_dstring_get_string(&limit_name);
 
1128
 
 
1129
            /* reuse earlier result */
 
1130
            if ((rql=lGetElemStr(a->limit_list, RQL_name, limit_s))) {
 
1131
               result = (dispatch_t)lGetInt(rql, RQL_result);
 
1132
               tslots = MIN(tslots, lGetInt(rql, RQL_slots));
 
1133
               tslots_qend = MIN(tslots_qend, lGetInt(rql, RQL_slots_qend));
 
1134
 
 
1135
               DPRINTF(("parallel_rqs_slots_by_time(%s@%s) result %d slots %d slots_qend %d for "SFQ" (cache)\n",
 
1136
                     queue, host, result, tslots, tslots_qend, limit_s));
 
1137
            } else {
 
1138
               int ttslots = INT_MAX;
 
1139
               int ttslots_qend = INT_MAX;
 
1140
 
 
1141
               for_each(limit, lGetList(rule, RQR_limit)) {
 
1142
                  const char *limit_name = lGetString(limit, RQRL_name);
 
1143
 
 
1144
                  lListElem *raw_centry = centry_list_locate(a->centry_list, limit_name);
 
1145
                  lList *job_centry_list = lGetList(a->job, JB_hard_resource_list);
 
1146
                  lListElem *job_centry = centry_list_locate(job_centry_list, limit_name);
 
1147
                  if (raw_centry == NULL) {
 
1148
                     DPRINTF(("ignoring limit %s because not defined", limit_name));
 
1149
                     continue;
 
1150
                  } else {
 
1151
                     DPRINTF(("checking limit %s\n", lGetString(raw_centry, CE_name)));
 
1152
                  }
 
1153
 
 
1154
                  /* found a rule, now check limit */
 
1155
                  if (lGetBool(raw_centry, CE_consumable)) {
 
1156
 
 
1157
                     rqs_get_rue_string(&rue_string, rule, user, project, host, queue, pe);
 
1158
 
 
1159
                     if (rqs_set_dynamical_limit(limit, a->gep, exec_host, a->centry_list)) {
 
1160
                        int tttslots;
 
1161
                        int tttslots_qend;
 
1162
                        result = parallel_limit_slots_by_time(a, job_centry_list, &tttslots, &tttslots_qend, raw_centry, limit, &rue_string);
 
1163
                        ttslots = MIN(ttslots, tttslots);
 
1164
                        ttslots_qend = MIN(ttslots_qend, tttslots_qend);
 
1165
                        if (result != DISPATCH_OK) {
 
1166
                           break;
 
1167
                        }
 
1168
                     } else {
 
1169
                        result = DISPATCH_NEVER_CAT;
 
1170
                        break;
 
1171
                     }
 
1172
                  } else {
 
1173
                     char availability_text[2048];
 
1174
 
 
1175
                     lSetString(raw_centry, CE_stringval, lGetString(limit, RQRL_value));
 
1176
                     if (compare_complexes(1, raw_centry, job_centry, availability_text, false, false) != 1) {
 
1177
                        result = DISPATCH_NEVER_CAT;
 
1178
                        break;
 
1179
                     }
 
1180
                  }
 
1181
               }
 
1182
 
 
1183
               DPRINTF(("parallel_rqs_slots_by_time(%s@%s) result %d slots %d slots_qend %d for "SFQ" (fresh)\n",
 
1184
                     queue, host, result, ttslots, ttslots_qend, limit_s));
 
1185
 
 
1186
               /* store result for reuse */
 
1187
               rql = lAddElemStr(&(a->limit_list), RQL_name, limit_s, RQL_Type);
 
1188
               lSetInt(rql, RQL_result, result);
 
1189
               lSetInt(rql, RQL_slots, ttslots);
 
1190
               lSetInt(rql, RQL_slots_qend, ttslots_qend);
 
1191
 
 
1192
               tslots = MIN(tslots, ttslots);
 
1193
               tslots_qend = MIN(tslots_qend, ttslots_qend);
 
1194
 
 
1195
            }
 
1196
 
 
1197
            if (result != DISPATCH_OK || (tslots == 0 && ( a->is_reservation || !a->care_reservation || tslots_qend == 0))) {
 
1198
               DPRINTF(("RQS PARALLEL SORT OUT\n"));
 
1199
               schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNRQSGLOBAL_SS,
 
1200
                     sge_dstring_get_string(&rue_string), sge_dstring_get_string(&rule_name));
 
1201
               rqs_exceeded_sort_out_par(a, rule, &rule_name, queue, host);
 
1202
            }
 
1203
 
 
1204
            if (result != DISPATCH_OK || tslots == 0) {
 
1205
               break;
 
1206
            }
 
1207
         }
 
1208
      }
 
1209
      sge_dstring_free(&rue_string);
 
1210
      sge_dstring_free(&rule_name);
 
1211
      sge_dstring_free(&limit_name);
 
1212
   }
 
1213
 
 
1214
   *slots = tslots;
 
1215
   *slots_qend = tslots_qend;
 
1216
 
 
1217
   DPRINTF(("parallel_rqs_slots_by_time(%s@%s) finalresult %d slots %d slots_qend %d\n", 
 
1218
         queue, host, result, *slots, *slots_qend));
 
1219
 
 
1220
   DRETURN(result);
 
1221
}
 
1222
 
 
1223
/****** sge_resource_quota_schedd/rqs_limitation_reached() *********************
 
1224
*  NAME
 
1225
*     rqs_limitation_reached() -- is the limitation reached for a queue instance
 
1226
*
 
1227
*  SYNOPSIS
 
1228
*     static bool rqs_limitation_reached(sge_assignment_t *a, lListElem *rule, 
 
1229
*     const char* host, const char* queue) 
 
1230
*
 
1231
*  FUNCTION
 
1232
*     The function verifies no limitation is reached for the specific job request
 
1233
*     and queue instance
 
1234
*
 
1235
*  INPUTS
 
1236
*     sge_assignment_t *a    - job info structure
 
1237
*     const lListElem *rule        - rqsource quota rule (RQR_Type)
 
1238
*     const char* host       - host name
 
1239
*     const char* queue      - queue name
 
1240
*    u_long32 *start         - start time of job
 
1241
*
 
1242
*  RESULT
 
1243
*     static dispatch_t - DISPATCH_OK job can be scheduled
 
1244
*                         DISPATCH_NEVER_CAT no jobs of this category will be scheduled
 
1245
*                         DISPATCH_NOT_AT_TIME job can be scheduled later
 
1246
*                         DISPATCH_MISSING_ATTR rule does not match requested attributes
 
1247
*
 
1248
*  NOTES
 
1249
*     MT-NOTE: rqs_limitation_reached() is not MT safe 
 
1250
*
 
1251
*******************************************************************************/
 
1252
static dispatch_t rqs_limitation_reached(sge_assignment_t *a, const lListElem *rule, const char* host, const char* queue, u_long32 *start) 
 
1253
{
 
1254
   dispatch_t ret = DISPATCH_MISSING_ATTR;
 
1255
   lList *limit_list = NULL;
 
1256
   lListElem * limit = NULL;
 
1257
   static lListElem *implicit_slots_request = NULL;
 
1258
   lListElem *exec_host = host_list_locate(a->host_list, host);
 
1259
   dstring rue_name = DSTRING_INIT;
 
1260
   dstring reason = DSTRING_INIT;
 
1261
 
 
1262
   DENTER(TOP_LAYER, "rqs_limitation_reached");
 
1263
 
 
1264
    if (implicit_slots_request == NULL) {
 
1265
      implicit_slots_request = lCreateElem(CE_Type);
 
1266
      lSetString(implicit_slots_request, CE_name, SGE_ATTR_SLOTS);
 
1267
      lSetString(implicit_slots_request, CE_stringval, "1");
 
1268
      lSetDouble(implicit_slots_request, CE_doubleval, 1);
 
1269
   }
 
1270
 
 
1271
   limit_list = lGetList(rule, RQR_limit);
 
1272
   for_each(limit, limit_list) {
 
1273
      
 
1274
      const char *limit_name = lGetString(limit, RQRL_name);
 
1275
 
 
1276
      lListElem *raw_centry = centry_list_locate(a->centry_list, limit_name);
 
1277
      bool is_forced = lGetUlong(raw_centry, CE_requestable) == REQU_FORCED ? true : false;
 
1278
      lList *job_centry_list = lGetList(a->job, JB_hard_resource_list);
 
1279
      lListElem *job_centry = centry_list_locate(job_centry_list, limit_name);
 
1280
 
 
1281
      if (raw_centry == NULL) {
 
1282
         DPRINTF(("ignoring limit %s because not defined", limit_name));
 
1283
         continue;
 
1284
      } else {
 
1285
         DPRINTF(("checking limit %s\n", lGetString(raw_centry, CE_name)));
 
1286
      }
 
1287
 
 
1288
      /* check for implicit slot and default request */
 
1289
      if (job_centry == NULL) {
 
1290
         if (strcmp(lGetString(raw_centry, CE_name), SGE_ATTR_SLOTS) == 0) {
 
1291
            job_centry = implicit_slots_request;
 
1292
         } else if (lGetString(raw_centry, CE_default) != NULL && lGetBool(raw_centry, CE_consumable)) {
 
1293
            double request;
 
1294
            parse_ulong_val(&request, NULL, lGetUlong(raw_centry, CE_valtype), lGetString(raw_centry, CE_default), NULL, 0);
 
1295
 
 
1296
            /* default requests with zero value are ignored */
 
1297
            if (request == 0.0) {
 
1298
               continue;
 
1299
            }
 
1300
            lSetString(raw_centry, CE_stringval, lGetString(raw_centry, CE_default));
 
1301
            lSetDouble(raw_centry, CE_doubleval, request);
 
1302
            job_centry = raw_centry; 
 
1303
            DPRINTF(("using default request for %s!\n", lGetString(raw_centry, CE_name)));
 
1304
         } else if (is_forced == true) {
 
1305
            schedd_mes_add(a->job_id, SCHEDD_INFO_NOTREQFORCEDRES); 
 
1306
            ret = DISPATCH_NEVER_CAT;
 
1307
            break;
 
1308
         } else {
 
1309
            /* ignoring because centry was not requested and is no consumable */
 
1310
            DPRINTF(("complex not requested!\n"));
 
1311
            continue;
 
1312
         }
 
1313
      }
 
1314
 
 
1315
      {
 
1316
         lList *tmp_centry_list = lCreateList("", CE_Type);
 
1317
         lList *tmp_rue_list = lCreateList("", RUE_Type);
 
1318
         lListElem *tmp_centry_elem = NULL;
 
1319
         lListElem *tmp_rue_elem = NULL;
 
1320
            
 
1321
         if (rqs_set_dynamical_limit(limit, a->gep, exec_host, a->centry_list)) {
 
1322
            lList *rue_list = lGetList(limit, RQRL_usage);
 
1323
            u_long32 tmp_time = a->start;
 
1324
 
 
1325
            /* create tmp_centry_list */
 
1326
            tmp_centry_elem = lCopyElem(raw_centry);
 
1327
            lSetString(tmp_centry_elem, CE_stringval, lGetString(limit, RQRL_value));
 
1328
            lSetDouble(tmp_centry_elem, CE_doubleval, lGetDouble(limit, RQRL_dvalue));
 
1329
            lAppendElem(tmp_centry_list, tmp_centry_elem);
 
1330
 
 
1331
            /* create tmp_rue_list */
 
1332
            rqs_get_rue_string(&rue_name, rule, a->user, a->project, host, queue, NULL);
 
1333
            tmp_rue_elem = lCopyElem(lGetElemStr(rue_list, RUE_name, sge_dstring_get_string(&rue_name)));
 
1334
            if (tmp_rue_elem == NULL) {
 
1335
               tmp_rue_elem = lCreateElem(RUE_Type);
 
1336
            }
 
1337
            lSetString(tmp_rue_elem, RUE_name, limit_name);
 
1338
            lAppendElem(tmp_rue_list, tmp_rue_elem);
 
1339
           
 
1340
            sge_dstring_clear(&reason);
 
1341
            ret = ri_time_by_slots(a, job_centry, NULL, tmp_centry_list,  tmp_rue_list,
 
1342
                                       NULL, &reason, false, 1, DOMINANT_LAYER_RQS, 0.0, &tmp_time,
 
1343
                                       SGE_RQS_NAME);
 
1344
            if (ret != DISPATCH_OK) {
 
1345
               DPRINTF(("denied because: %s\n", sge_dstring_get_string(&reason)));
 
1346
               lFreeList(&tmp_rue_list);
 
1347
               lFreeList(&tmp_centry_list);
 
1348
               break;
 
1349
            }
 
1350
 
 
1351
            if (a->is_reservation && ret == DISPATCH_OK) {
 
1352
               *start = tmp_time;
 
1353
            }
 
1354
 
 
1355
            lFreeList(&tmp_rue_list);
 
1356
            lFreeList(&tmp_centry_list);
 
1357
         }
 
1358
      }
 
1359
   }
 
1360
 
 
1361
   sge_dstring_free(&reason);
 
1362
   sge_dstring_free(&rue_name);
 
1363
 
 
1364
   DRETURN(ret);
 
1365
}
 
1366
 
 
1367
/****** sge_resource_quota_schedd/rqs_by_slots() ***********************************
 
1368
*  NAME
 
1369
*     rqs_by_slots() -- Check queue instance suitability due to RQS
 
1370
*
 
1371
*  SYNOPSIS
 
1372
*     dispatch_t rqs_by_slots(sge_assignment_t *a, const char *queue, 
 
1373
*     const char *host, u_long32 *tt_rqs_all, bool *is_global, 
 
1374
*     dstring *rue_string, dstring *limit_name, dstring *rule_name) 
 
1375
*
 
1376
*  FUNCTION
 
1377
*     Checks (or determines earliest time) queue instance suitability 
 
1378
*     according to resource quota set limits. 
 
1379
*     
 
1380
*     For performance reasons RQS verification results are cached in 
 
1381
*     a->limit_list. In addition unsuited queues and hosts are collected
 
1382
*     in a->skip_cqueue_list and a->skip_host_list so that ruling out 
 
1383
*     chunks of queue instance becomes quite cheap.
 
1384
*
 
1385
*  INPUTS
 
1386
*     sge_assignment_t *a  - assignment
 
1387
*     const char *queue    - cluster queue name
 
1388
*     const char *host     - host name
 
1389
*     u_long32 *tt_rqs_all - returns earliest time over all resource quotas
 
1390
*     bool *is_global      - returns true if result is valid for any other queue
 
1391
*     dstring *rue_string  - caller maintained buffer
 
1392
*     dstring *limit_name  - caller maintained buffer
 
1393
*     dstring *rule_name   - caller maintained buffer
 
1394
*     u_long32 tt_best     - time of best solution found so far
 
1395
*
 
1396
*  RESULT
 
1397
*     static dispatch_t - usual return values
 
1398
*
 
1399
*  NOTES
 
1400
*     MT-NOTE: rqs_by_slots() is MT safe 
 
1401
*******************************************************************************/
 
1402
dispatch_t rqs_by_slots(sge_assignment_t *a, const char *queue, const char *host, 
 
1403
  u_long32 *tt_rqs_all, bool *is_global, dstring *rue_string, dstring *limit_name, dstring *rule_name, u_long32 tt_best)
 
1404
{
 
1405
   lListElem *rqs;
 
1406
   dispatch_t result = DISPATCH_OK;
 
1407
 
 
1408
   DENTER(TOP_LAYER, "rqs_by_slots");
 
1409
 
 
1410
   *is_global = false;
 
1411
 
 
1412
   if (a->pi && lGetNumberOfElem(a->rqs_list) > 0) {
 
1413
      a->pi->seq_rqs++;
 
1414
   }
 
1415
 
 
1416
   for_each(rqs, a->rqs_list) {
 
1417
      u_long32 tt_rqs = a->start;
 
1418
      const char *user = a->user;
 
1419
      const char *group = a->group;
 
1420
      const char *project = a->project;
 
1421
      const lListElem *rule;
 
1422
 
 
1423
      if (!lGetBool(rqs, RQS_enabled)) {
 
1424
         continue;
 
1425
      }
 
1426
 
 
1427
      sge_dstring_clear(rule_name);
 
1428
      rule = rqs_get_matching_rule(rqs, user, group, project, NULL, host, queue, a->acl_list, a->hgrp_list, rule_name);
 
1429
      if (rule != NULL) {
 
1430
         const char *limit;
 
1431
         lListElem *rql;
 
1432
 
 
1433
         /* need unique identifier for cache */
 
1434
         rqs_get_rue_string(rue_string, rule, user, project, host, queue, NULL);
 
1435
         sge_dstring_sprintf(limit_name, "%s=%s", sge_dstring_get_string(rule_name), sge_dstring_get_string(rue_string));
 
1436
         limit = sge_dstring_get_string(limit_name);
 
1437
 
 
1438
         /* check limit or reuse earlier results */
 
1439
         if ((rql=lGetElemStr(a->limit_list, RQL_name, limit))) {
 
1440
            tt_rqs = lGetUlong(rql, RQL_time);
 
1441
            result = (dispatch_t)lGetInt(rql, RQL_result);
 
1442
         } else {
 
1443
            /* Check booked usage */
 
1444
            result = rqs_limitation_reached(a, rule, host, queue, &tt_rqs);
 
1445
 
 
1446
            rql = lAddElemStr(&(a->limit_list), RQL_name, limit, RQL_Type);
 
1447
            lSetInt(rql, RQL_result, result);
 
1448
            lSetUlong(rql, RQL_time, tt_rqs);
 
1449
 
 
1450
            if (result != DISPATCH_OK && result != DISPATCH_MISSING_ATTR) {
 
1451
               schedd_mes_add(a->job_id, SCHEDD_INFO_CANNOTRUNRQSGLOBAL_SS, 
 
1452
                     sge_dstring_get_string(rue_string), sge_dstring_get_string(rule_name));
 
1453
               if (rqs_exceeded_sort_out(a, rule, rule_name, queue, host)) {
 
1454
                  *is_global = true;
 
1455
               }
 
1456
            }
 
1457
         }
 
1458
 
 
1459
         if (result == DISPATCH_MISSING_ATTR) {
 
1460
            result = DISPATCH_OK;
 
1461
            continue;
 
1462
         }
 
1463
         if (result != DISPATCH_OK)
 
1464
            break;
 
1465
 
 
1466
         if (a->is_reservation && tt_rqs >= tt_best) {
 
1467
            /* no need to further investigate these ones */
 
1468
            if (rqs_exceeded_sort_out(a, rule, rule_name, queue, host))
 
1469
               *is_global = true;
 
1470
         }
 
1471
 
 
1472
         *tt_rqs_all = MAX(*tt_rqs_all, tt_rqs);
 
1473
      }
 
1474
   }
 
1475
 
 
1476
   if (!rqs) 
 
1477
      result = DISPATCH_OK;
 
1478
 
 
1479
   if (result == DISPATCH_OK || result == DISPATCH_MISSING_ATTR) {
 
1480
      DPRINTF(("rqs_by_slots(%s@%s) returns <at specified time> "sge_U32CFormat"\n", queue, host, tt_rqs_all));
 
1481
   } else {
 
1482
      DPRINTF(("rqs_by_slots(%s@%s) returns <later> "sge_U32CFormat" (%s)\n", queue, host, tt_rqs_all, *is_global?"global":"not global"));
 
1483
   }
 
1484
 
 
1485
   DRETURN(result);
 
1486
}