1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
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
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.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
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"
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"
53
#include "sched/sort_hosts.h"
55
#include "sched/sge_schedd_text.h"
56
#include "sched/schedd_message.h"
57
#include "uti/sge_parse_num_par.h"
60
static void rqs_can_optimize(const lListElem *rule, bool *host, bool *queue, sge_assignment_t *a);
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);
65
static bool is_cqueue_global(const lListElem *rule);
66
static bool is_host_global(const lListElem *rule);
68
static bool is_cqueue_expand(const lListElem *rule);
69
static bool is_host_expand(const lListElem *rule);
71
static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a);
72
static bool host_shadowed(const lListElem *rule, sge_assignment_t *a);
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);
78
/****** sge_resource_quota_schedd/rqs_set_dynamical_limit() ***********************
80
* rqs_set_dynamical_limit() -- evaluate dynamical limit
83
* bool rqs_set_dynamical_limit(lListElem *limit, lListElem
84
* *global_host, lListElem *exec_host, lList *centry)
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).
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
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)
103
* MT-NOTE: rqs_set_dynamical_limit() is MT safe
105
*******************************************************************************/
107
rqs_set_dynamical_limit(lListElem *limit, lListElem *global_host, lListElem *exec_host, lList *centry) {
109
DENTER(TOP_LAYER, "rqs_set_dynamical_limit");
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);
120
/****** sge_resource_quota_schedd/rqs_match_assignment() ***********************
122
* rqs_match_assignment() -- match resource quota rule any queue instance
125
* static bool rqs_match_assignment(const lListElem *rule, sge_assignment_t
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
133
* Note: As long as rqs_match_assignment() is not used for parallel jobs
134
* passing NULL as PE request is perfectly fine.
137
* const lListElem *rule - Resource quota rule
138
* sge_assignment_t *a - Scheduler assignment
141
* static bool - True if it matches
144
* MT-NOTE: rqs_match_assignment() is MT safe
145
*******************************************************************************/
146
static bool rqs_match_assignment(const lListElem *rule, sge_assignment_t *a)
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;
154
/****** sge_resource_quota_schedd/cqueue_shadowed() ****************************
156
* cqueue_shadowed() -- Check for cluster queue rule before current rule
159
* static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a)
162
* Check whether there is any cluster queue specific rule before the
166
* const lListElem *rule - Current rule
167
* sge_assignment_t *a - Scheduler assignment
170
* static bool - True if shadowed
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 )
178
* MT-NOTE: cqueue_shadowed() is MT safe
179
*******************************************************************************/
180
static bool cqueue_shadowed(const lListElem *rule, sge_assignment_t *a)
182
while ((rule = lPrev(rule))) {
183
if (rqs_match_assignment(rule, a) && !is_cqueue_global(rule)) {
190
/****** sge_resource_quota_schedd/host_shadowed() ******************************
192
* host_shadowed() -- Check for host rule before current rule
195
* static bool host_shadowed(const lListElem *rule, sge_assignment_t *a)
198
* Check whether there is any host specific rule before the
202
* const lListElem *rule - Current rule
203
* sge_assignment_t *a - Scheduler assignment
206
* static bool - True if shadowed
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 )
214
* MT-NOTE: host_shadowed() is MT safe
215
*******************************************************************************/
216
static bool host_shadowed(const lListElem *rule, sge_assignment_t *a)
218
while ((rule = lPrev(rule))) {
219
if (rqs_match_assignment(rule, a) && !is_host_global(rule)) {
226
/****** sge_resource_quota_schedd/cqueue_shadowed_by() *************************
228
* cqueue_shadowed_by() -- Check rules shadowing current cluster queue rule
231
* static bool cqueue_shadowed_by(const char *cqname, const lListElem *rule,
232
* sge_assignment_t *a)
235
* Check if cluster queue in current rule is shadowed.
238
* const char *cqname - Cluster queue name to check
239
* const lListElem *rule - Current rule
240
* sge_assignment_t *a - Assignment
243
* static bool - True if shadowed
246
* limits queues Q001,Q002 to F001=1
247
* limits queues Q002,Q003 to F001=1 (--> returns 'true' for Q002 and 'false' for Q003)
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)
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)) {
264
/****** sge_resource_quota_schedd/host_shadowed_by() ***************************
266
* host_shadowed_by() -- ???
269
* static bool host_shadowed_by(const char *host, const lListElem *rule,
270
* sge_assignment_t *a)
273
* Check if host in current rule is shadowed.
276
* const char *cqname - Host name to check
277
* const lListElem *rule - Current rule
278
* sge_assignment_t *a - Assignment
281
* static bool - True if shadowed
284
* limits hosts host1,host2 to F001=1
285
* limits hosts host2,host3 to F001=1 (--> returns 'true' for host2 and 'false' for host3)
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)
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)) {
302
/****** sge_resource_quota_schedd/rqs_can_optimize() ***************************
304
* rqs_can_optimize() -- Poke whether a queue/host negation can be made
307
* static void rqs_can_optimize(const lListElem *rule, bool *host, bool
308
* *queue, sge_assignment_t *a)
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
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
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)
327
bool host_shadowed = false, queue_shadowed = false;
329
const lListElem *prev = rule;
330
while ((prev = lPrev(prev))) {
331
if (!rqs_match_assignment(rule, a))
333
if (!is_host_global(prev))
334
host_shadowed = true;
335
if (!is_cqueue_global(prev))
336
queue_shadowed = true;
339
*host = host_shadowed;
340
*queue = queue_shadowed;
345
/****** sge_resource_quota_schedd/rqs_excluded_cqueues() ***********************
347
* rqs_excluded_cqueues() -- Find excluded queues
350
* static void rqs_excluded_cqueues(const lListElem *rule, sge_assignment_t *a)
353
* Find queues that are excluded by previous rules.
356
* const lListElem *rule - The rule
357
* sge_assignment_t *a - Scheduler assignement
360
* limit projects {*} queues !Q001 to F001=1
361
* limit to F001=0 ( ---> returns Q001 in a->skip_cqueue_list)
364
* MT-NOTE: rqs_excluded_cqueues() is MT safe
365
*******************************************************************************/
366
static void rqs_excluded_cqueues(const lListElem *rule, sge_assignment_t *a)
369
const lListElem *prev;
370
int ignored = 0, excluded = 0;
372
DENTER(TOP_LAYER, "rqs_excluded_cqueues");
374
for_each (cq, *(object_type_get_master_list(SGE_TYPE_CQUEUE))) {
375
const char *cqname = lGetString(cq, CQ_name);
378
if (lGetElemStr(a->skip_cqueue_list, CTI_name, cqname)) {
384
while ((prev = lPrev(prev))) {
385
if (!rqs_match_assignment(rule, a))
388
if (rqs_filter_match(lGetObject(prev, RQR_filter_queues), FILTER_QUEUES, cqname, NULL, NULL, NULL)) {
394
lAddElemStr(&(a->skip_cqueue_list), CTI_name, cqname, CTI_Type);
399
if (ignored + excluded == 0) {
400
CRITICAL((SGE_EVENT, "not a single queue excluded in rqs_excluded_cqueues()\n"));
406
/****** sge_resource_quota_schedd/rqs_excluded_hosts() *************************
408
* rqs_excluded_hosts() -- Find excluded hosts
411
* static void rqs_excluded_hosts(const lListElem *rule, sge_assignment_t *a)
414
* Find hosts that are excluded by previous rules.
417
* const lListElem *rule - The rule
418
* sge_assignment_t *a - Scheduler assignement
421
* limit projects {*} queues !gridware to F001=1
422
* limit to F001=0 ( ---> returns gridware in skip_host_list)
425
* MT-NOTE: rqs_excluded_hosts() is MT safe
426
*******************************************************************************/
427
static void rqs_excluded_hosts(const lListElem *rule, sge_assignment_t *a)
430
const lListElem *prev;
431
int ignored = 0, excluded = 0;
433
DENTER(TOP_LAYER, "rqs_excluded_hosts");
435
for_each (eh, a->host_list) {
436
const char *hname = lGetHost(eh, EH_name);
439
if (lGetElemStr(a->skip_host_list, CTI_name, hname)) {
445
while ((prev = lPrev(prev))) {
446
if (!rqs_match_assignment(rule, a))
449
if (rqs_filter_match(lGetObject(prev, RQR_filter_hosts), FILTER_HOSTS, hname, NULL, a->hgrp_list, NULL)) {
455
lAddElemStr(&(a->skip_host_list), CTI_name, hname, CTI_Type);
460
if (ignored + excluded == 0) {
461
CRITICAL((SGE_EVENT, "not a single host excluded in rqs_excluded_hosts()\n"));
467
/****** sge_resource_quota_schedd/rqs_expand_cqueues() *************************
469
* rqs_expand_cqueues() -- Add all matching cqueues to the list
472
* void rqs_expand_cqueues(const lListElem *rule)
475
* The names of all cluster queues that match the rule are added to
476
* the skip list without duplicates.
479
* const lListElem *rule - RQR_Type
482
* MT-NOTE: rqs_expand_cqueues() is not MT safe
483
*******************************************************************************/
484
static void rqs_expand_cqueues(const lListElem *rule, sge_assignment_t *a)
488
lListElem *qfilter = lGetObject(rule, RQR_filter_queues);
490
DENTER(TOP_LAYER, "rqs_expand_cqueues");
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))
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);
504
/****** sge_resource_quota_schedd/rqs_expand_hosts() ***************************
506
* rqs_expand_hosts() -- Add all matching hosts to the list
509
* void rqs_expand_hosts(const lListElem *rule, lList **skip_host_list,
510
* const lList *host_list, lList *hgrp_list)
513
* The names of all hosts that match the rule are added to
514
* the skip list without duplicates.
517
* const lListElem *rule - RQR_Type
518
* const lList *host_list - EH_Type
521
* MT-NOTE: rqs_expand_hosts() is MT safe
522
*******************************************************************************/
523
static void rqs_expand_hosts(const lListElem *rule, sge_assignment_t *a)
527
lListElem *hfilter = lGetObject(rule, RQR_filter_hosts);
529
for_each (eh, a->host_list) {
530
hname = lGetHost(eh, EH_name);
531
if (lGetElemStr(a->skip_host_list, CTI_name, hname))
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);
540
static bool is_global(const lListElem *rule, int nm)
542
lListElem *filter = lGetObject(rule, nm);
545
if (lGetSubStr(filter, ST_name, "*", RQRF_scope) && lGetNumberOfElem(lGetList(filter, RQRF_xscope))==0)
550
/****** sge_resource_quota_schedd/is_cqueue_global() ***************************
552
* is_cqueue_global() -- Global rule with regards to cluster queues?
555
* bool is_cqueue_global(const lListElem *rule)
558
* const lListElem *rule - RQR_Type
561
* bool - True if cluster queues play no role with the rule
564
* MT-NOTE: is_cqueue_global() is MT safe
565
*******************************************************************************/
566
static bool is_cqueue_global(const lListElem *rule)
568
return is_global(rule, RQR_filter_queues);
572
/****** sge_resource_quota_schedd/is_host_global() *****************************
574
* is_host_global() -- Global rule with regards to hosts?
577
* bool is_host_global(const lListElem *rule)
580
* Return true if hosts play no role with the rule
583
* const lListElem *rule - RQR_Type
586
* bool - True if hosts play no role with the rule
589
* MT-NOTE: is_host_global() is MT safe
590
*******************************************************************************/
591
static bool is_host_global(const lListElem *rule)
593
return is_global(rule, RQR_filter_hosts);
596
static bool is_expand(const lListElem *rule, int nm)
598
lListElem *filter = lGetObject(rule, nm);
599
if (filter && lGetBool(filter, RQRF_expand) == true)
606
/****** sge_resource_quota_schedd/is_host_expand() *****************************
608
* is_host_expand() -- Returns true if rule expands on hosts
611
* bool is_host_expand(const lListElem *rule)
614
* Returns true if rule expands on hosts.
617
* const lListElem *rule - RQR_Type
620
* bool - True if rule expands on hosts
623
* "hosts {*}" returns true
624
* "hosts @allhosts" returns false
627
* MT-NOTE: is_host_expand() is MT safe
628
*******************************************************************************/
629
static bool is_host_expand(const lListElem *rule)
631
return is_expand(rule, RQR_filter_hosts);
634
/****** sge_resource_quota_schedd/is_cqueue_expand() ***************************
636
* is_cqueue_expand() -- Returns true if rule expands on cluster queues
639
* bool is_cqueue_expand(const lListElem *rule)
642
* Returns true if rule expands on cluster queues.
645
* const lListElem *rule - RQR_Type
648
* bool - True if rule expands on hosts
651
* "queues {*}" returns true
652
* "queues Q001,Q002" returns false
655
* MT-NOTE: is_cqueue_expand() is MT safe
656
*******************************************************************************/
657
static bool is_cqueue_expand(const lListElem *rule)
659
return is_expand(rule, RQR_filter_queues);
662
/****** sge_resource_quota_schedd/rqs_exceeded_sort_out() **********************
664
* rqs_exceeded_sort_out() -- Rule out queues/hosts whenever possible
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)
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
675
* When a limitation was exeeded that applies to the entire
676
* cluster 'true' is returned, 'false' otherwise.
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
686
* bool - True upon global limits exceeding
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)
694
bool cq_global = is_cqueue_global(rule);
695
bool eh_global = is_host_global(rule);
697
DENTER(TOP_LAYER, "rqs_exceeded_sort_out");
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));
706
if (cq_global && eh_global) { /* failure at a global limit */
707
bool host_shadowed, queue_shadowed;
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)));
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));
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)));
737
if (!cq_global) { /* failure at a cluster queue limit */
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));
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));
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)));
758
/* must be (!eh_global) */
759
{ /* failure at a host limit */
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));
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));
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)));
781
/****** sge_resource_quota_schedd/rqs_exceeded_sort_out_par() ******************
783
* rqs_exceeded_sort_out_par() -- Rule out queues/hosts whenever possible
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*
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.
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
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)
808
if (rqs_exceeded_sort_out(a, rule, rule_name, queue_name, host_name)) {
809
rqs_expand_hosts(rule, a);
813
/****** sge_resource_quota_schedd/sge_user_is_referenced_in_rqs() ********************
815
* sge_user_is_referenced_in_rqs() -- search for user reference in rqs
818
* bool sge_user_is_referenced_in_rqs(const lList *rqs, const char *user,
822
* Search for a user reference in the resource quota sets
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
831
* bool - true if user was found
832
* false if user was not found
835
* MT-NOTE: sge_user_is_referenced_in_rqs() is MT safe
837
*******************************************************************************/
838
bool sge_user_is_referenced_in_rqs(const lList *rqs, const char *user, const char *group, lList *acl_list)
844
lList *rule_list = lGetList(ep, RQS_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)) {
863
/****** sge_resource_quota_schedd/check_and_debit_rqs_slots() *********************
865
* check_and_debit_rqs_slots() -- Determine RQS limit slot amount and debit
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)
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.
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
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)
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;
900
DENTER(TOP_LAYER, "parallel_check_and_debit_rqs_slots");
902
/* first step - see how many slots are left */
903
for_each(rqs, a->rqs_list) {
905
/* ignore disabled rule sets */
906
if (!lGetBool(rqs, RQS_enabled)) {
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);
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));
919
*slots = *slots_qend = 0;
923
if (*slots == 0 && *slots_qend == 0) {
928
/* second step - reduce number of remaining slots */
929
if (*slots != 0 || *slots_qend != 0) {
930
for_each(rqs, a->rqs_list) {
932
/* ignore disabled rule sets */
933
if (!lGetBool(rqs, RQS_enabled)) {
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);
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);
949
DPRINTF(("check_and_debit_rqs_slots(%s@%s) slots: %d slots_qend: %d\n", queue, host, *slots, *slots_qend));
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)
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;
963
DENTER(TOP_LAYER, "parallel_check_and_debit_rqs_slots");
965
for_each(rqs, a->rqs_list) {
967
/* ignore disabled rule sets */
968
if (!lGetBool(rqs, RQS_enabled)) {
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);
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);
988
/****** sge_resource_quota_schedd/parallel_limit_slots_by_time() ********************
990
* parallel_limit_slots_by_time() -- Determine number of slots avail. within
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)
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
1011
* static dispatch_t - DISPATCH_OK got an assignment
1012
* - DISPATCH_NEVER_CAT no assignment for all jobs af that category
1015
* MT-NOTE: parallel_limit_slots_by_time() is not MT safe
1018
* parallel_rc_slots_by_time
1019
*******************************************************************************/
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)
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;
1031
DENTER(TOP_LAYER, "parallel_limit_slots_by_time");
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);
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);
1044
lSetString(tmp_rue_elem, RUE_name, lGetString(limit, RQRL_name));
1045
lAppendElem(tmp_rue_list, tmp_rue_elem);
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);
1052
lFreeList(&tmp_centry_list);
1053
lFreeList(&tmp_rue_list);
1059
/****** sge_resource_quota_schedd/parallel_rqs_slots_by_time() ******************
1061
* parallel_rqs_slots_by_time() -- Dertermine number of slots avail within
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)
1069
* This function iterates for a queue instance over all resource quota sets
1070
* and evaluates the number of slots available.
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
1080
* static dispatch_t - DISPATCH_OK got an assignment
1081
* - DISPATCH_NEVER_CAT no assignment for all jobs af that category
1084
* MT-NOTE: parallel_rqs_slots_by_time() is not MT safe
1087
* ri_slots_by_time()
1089
*******************************************************************************/
1091
parallel_rqs_slots_by_time(sge_assignment_t *a, int *slots, int *slots_qend, const char *host, const char *queue)
1093
dispatch_t result = DISPATCH_OK;
1094
int tslots = INT_MAX;
1095
int tslots_qend = INT_MAX;
1097
DENTER(TOP_LAYER, "parallel_rqs_slots_by_time");
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;
1112
for_each(rqs, a->rqs_list) {
1113
lListElem *rule = NULL;
1114
lListElem *exec_host = host_list_locate(a->host_list, host);
1116
/* ignore disabled rule sets */
1117
if (!lGetBool(rqs, RQS_enabled)) {
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);
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);
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));
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));
1138
int ttslots = INT_MAX;
1139
int ttslots_qend = INT_MAX;
1141
for_each(limit, lGetList(rule, RQR_limit)) {
1142
const char *limit_name = lGetString(limit, RQRL_name);
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));
1151
DPRINTF(("checking limit %s\n", lGetString(raw_centry, CE_name)));
1154
/* found a rule, now check limit */
1155
if (lGetBool(raw_centry, CE_consumable)) {
1157
rqs_get_rue_string(&rue_string, rule, user, project, host, queue, pe);
1159
if (rqs_set_dynamical_limit(limit, a->gep, exec_host, a->centry_list)) {
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) {
1169
result = DISPATCH_NEVER_CAT;
1173
char availability_text[2048];
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;
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));
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);
1192
tslots = MIN(tslots, ttslots);
1193
tslots_qend = MIN(tslots_qend, ttslots_qend);
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);
1204
if (result != DISPATCH_OK || tslots == 0) {
1209
sge_dstring_free(&rue_string);
1210
sge_dstring_free(&rule_name);
1211
sge_dstring_free(&limit_name);
1215
*slots_qend = tslots_qend;
1217
DPRINTF(("parallel_rqs_slots_by_time(%s@%s) finalresult %d slots %d slots_qend %d\n",
1218
queue, host, result, *slots, *slots_qend));
1223
/****** sge_resource_quota_schedd/rqs_limitation_reached() *********************
1225
* rqs_limitation_reached() -- is the limitation reached for a queue instance
1228
* static bool rqs_limitation_reached(sge_assignment_t *a, lListElem *rule,
1229
* const char* host, const char* queue)
1232
* The function verifies no limitation is reached for the specific job request
1233
* and queue instance
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
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
1249
* MT-NOTE: rqs_limitation_reached() is not MT safe
1251
*******************************************************************************/
1252
static dispatch_t rqs_limitation_reached(sge_assignment_t *a, const lListElem *rule, const char* host, const char* queue, u_long32 *start)
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;
1262
DENTER(TOP_LAYER, "rqs_limitation_reached");
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);
1271
limit_list = lGetList(rule, RQR_limit);
1272
for_each(limit, limit_list) {
1274
const char *limit_name = lGetString(limit, RQRL_name);
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);
1281
if (raw_centry == NULL) {
1282
DPRINTF(("ignoring limit %s because not defined", limit_name));
1285
DPRINTF(("checking limit %s\n", lGetString(raw_centry, CE_name)));
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)) {
1294
parse_ulong_val(&request, NULL, lGetUlong(raw_centry, CE_valtype), lGetString(raw_centry, CE_default), NULL, 0);
1296
/* default requests with zero value are ignored */
1297
if (request == 0.0) {
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;
1309
/* ignoring because centry was not requested and is no consumable */
1310
DPRINTF(("complex not requested!\n"));
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;
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;
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);
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);
1337
lSetString(tmp_rue_elem, RUE_name, limit_name);
1338
lAppendElem(tmp_rue_list, tmp_rue_elem);
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,
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);
1351
if (a->is_reservation && ret == DISPATCH_OK) {
1355
lFreeList(&tmp_rue_list);
1356
lFreeList(&tmp_centry_list);
1361
sge_dstring_free(&reason);
1362
sge_dstring_free(&rue_name);
1367
/****** sge_resource_quota_schedd/rqs_by_slots() ***********************************
1369
* rqs_by_slots() -- Check queue instance suitability due to RQS
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)
1377
* Checks (or determines earliest time) queue instance suitability
1378
* according to resource quota set limits.
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.
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
1397
* static dispatch_t - usual return values
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)
1406
dispatch_t result = DISPATCH_OK;
1408
DENTER(TOP_LAYER, "rqs_by_slots");
1412
if (a->pi && lGetNumberOfElem(a->rqs_list) > 0) {
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;
1423
if (!lGetBool(rqs, RQS_enabled)) {
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);
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);
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);
1443
/* Check booked usage */
1444
result = rqs_limitation_reached(a, rule, host, queue, &tt_rqs);
1446
rql = lAddElemStr(&(a->limit_list), RQL_name, limit, RQL_Type);
1447
lSetInt(rql, RQL_result, result);
1448
lSetUlong(rql, RQL_time, tt_rqs);
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)) {
1459
if (result == DISPATCH_MISSING_ATTR) {
1460
result = DISPATCH_OK;
1463
if (result != DISPATCH_OK)
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))
1472
*tt_rqs_all = MAX(*tt_rqs_all, tt_rqs);
1477
result = DISPATCH_OK;
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));
1482
DPRINTF(("rqs_by_slots(%s@%s) returns <later> "sge_U32CFormat" (%s)\n", queue, host, tt_rqs_all, *is_global?"global":"not global"));