diff --git a/src/include/attribute.h b/src/include/attribute.h index 1016754..c4a6688 100644 --- a/src/include/attribute.h +++ b/src/include/attribute.h @@ -106,7 +106,7 @@ /* define the size of fields in the structures */ -#define ATRFLAG 16 +#define ATRFLAG 18 #define ATRTYPE 6 /* sync w/ATR_TYPE_* (see #defines below) */ #define ATRPART 3 @@ -262,6 +262,9 @@ typedef struct attribute_def attribute_def; #define ATR_DFLAG_RASSN 0x4000 /* resc to be summed in resources_used */ #define ATR_DFLAG_RMOMIG 0x8000 /* resource to be ignored by mom */ +#define ATR_DFLAG_SELECT_PROC 0x10000 /* per-proc resource in the select and nodespec statements */ +#define ATR_DFLAG_SELECT_MOM 0x20000 /* per-node resource in the select and nodespec statements */ + /* combination defines for permission field */ #define READ_ONLY ATR_DFLAG_USRD | ATR_DFLAG_OPRD | ATR_DFLAG_MGRD diff --git a/src/server/node_manager.c b/src/server/node_manager.c index 65fcd1e..2624a68 100644 --- a/src/server/node_manager.c +++ b/src/server/node_manager.c @@ -174,15 +174,15 @@ extern int SvrNodeCt; #define MAX_BM 64 #endif -int hasprop(struct pbsnode *, struct prop *); +int hasprop(struct pbsnode *, struct prop *, int proc_count); void send_cluster_addrs(struct work_task *); int add_cluster_addrs(int); int is_compose(int, int); -int add_job_to_node(struct pbsnode *,struct pbssubn *,short,job *,int); +int add_job_to_node(struct pbsnode *,struct pbssubn *,short,job *,int,int); int node_satisfies_request(struct pbsnode *,char *); int reserve_node(struct pbsnode *,short,job *,char *,struct howl **); int build_host_list(struct howl **,struct pbssubn *,struct pbsnode *); -void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, +void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, int, enum batch_op op); /* @@ -2446,7 +2446,7 @@ void node_unreserve( -int hasres(struct pbsnode *pnode, char *name, char *value) +int hasres(struct pbsnode *pnode, char *name, char *value, int proc_count) { resource_def *rd; resource *total, *used, req, tmp; @@ -2457,6 +2457,9 @@ int hasres(struct pbsnode *pnode, char *name, char *value) if (rd == NULL) /* unknown resource */ return 0; + if ((rd->rs_flags & (ATR_DFLAG_SELECT_PROC | ATR_DFLAG_SELECT_MOM)) == 0) + return 1; /* this resource is not per-proc or per-node and therefore not checked */ + total = find_resc_entry(&pnode->attributes[0],rd); if (total == NULL) /* resource not present on node */ @@ -2465,6 +2468,32 @@ int hasres(struct pbsnode *pnode, char *name, char *value) used = find_resc_entry(&pnode->attributes[1],rd); rd->rs_decode(&req.rs_value,0,name,value); /* encode the request into resource */ + + /* now we need to determine if this resource is per-proc or per-node */ + /* if it is per-proc, we need to multiply the value accordingly by the number of procs */ + /* because there is no universal logic for this, we simply have to manually multiply the value */ + if ((rd->rs_flags & ATR_DFLAG_SELECT_PROC) != 0) + { + switch (rd->rs_type) + { + case ATR_TYPE_LONG: + req.rs_value.at_val.at_long *= proc_count; + break; + case ATR_TYPE_LL: + req.rs_value.at_val.at_ll *= proc_count; + break; + case ATR_TYPE_SHORT: + req.rs_value.at_val.at_short *= proc_count; + break; + case ATR_TYPE_SIZE: + /* keep it in the same unit */ + req.rs_value.at_val.at_size.atsv_num *= proc_count; + break; + default: /* we can't multiply non-numeric values */ + break; /* ATR_TYPE_JINFOP, ATR_TYPE_ACL, ATR_TYPE_RESC, ATR_TYPE_CHAR, ATR_TYPE_STR, ATR_TYPE_ARST, ATR_TYPE_LIST */ + } + } + rd->rs_set(&tmp.rs_value,&total->rs_value,SET); /* set the total */ if (used != NULL) @@ -2488,9 +2517,9 @@ int hasres(struct pbsnode *pnode, char *name, char *value) */ int hasprop( - struct pbsnode *pnode, - struct prop *props) + struct prop *props, + int proc_count ) { @@ -2519,7 +2548,7 @@ int hasprop( } else { - if (!hasres(pnode,props->name,props->value)) + if (!hasres(pnode,props->name,props->value,proc_count)) return 0; } } @@ -2657,7 +2686,7 @@ static int search( continue; */ - if (!hasprop(pnode, glorf)) + if (!hasprop(pnode, glorf, vpreq)) continue; if ((skip == SKIP_NONE) || (skip == SKIP_NONE_REUSE)) @@ -2728,7 +2757,7 @@ static int search( (vpreq < (pnode->nd_nsnfree + pnode->nd_nsnshared))) continue; - if (!hasprop(pnode, glorf)) + if (!hasprop(pnode, glorf, vpreq)) continue; pnode->nd_flag = conflict; @@ -3023,7 +3052,7 @@ static int listelem( if (pnode->nd_ntype == NTYPE_CLUSTER) { - if (hasprop(pnode, prop) && hasppn(pnode, node_req, SKIP_NONE)) + if (hasprop(pnode, prop, node_req) && hasppn(pnode, node_req, SKIP_NONE)) hit++; if (hit == num) @@ -3310,7 +3339,7 @@ static char *nodespec_app(const char *spec, const char *app) * @param exclusive 0 if shared, 1 if exclusive, 2 if node exclusive * @return NULL on failure or allocated modified spec */ -static char *nodespec_expand(const char *spec, int *exclusive) +static char *nodespec_expand(job *pjob, const char *spec, int *exclusive) { char *result, *globs, *cp, *tmp; static char shared[] = "shared"; /* shared */ @@ -3327,10 +3356,7 @@ static char *nodespec_expand(const char *spec, int *exclusive) globs = strdup(globs); if (globs == NULL) /* alloc failure */ - { - free(result); - return NULL; - } + goto fail; /* glob now stores the global part of the nodespec * - go thru each part of the global spec and append @@ -3354,9 +3380,8 @@ static char *nodespec_expand(const char *spec, int *exclusive) tmp = nodespec_app(result, cp); if (tmp == NULL) /* alloc failure */ { - free(result); free(globs); - return NULL; + goto fail; } free(result); @@ -3368,22 +3393,21 @@ static char *nodespec_expand(const char *spec, int *exclusive) { *exclusive = 0; free(globs); - return result; + goto done_stage1; } if (!strcmp(globs, excl)) /* #excl */ { *exclusive = 1; free(globs); - return result; + goto done_stage1; } tmp = nodespec_app(result, globs); if (tmp == NULL) /* alloc failure */ { - free(result); free(globs); - return NULL; + goto fail; } free(result); @@ -3392,7 +3416,64 @@ static char *nodespec_expand(const char *spec, int *exclusive) free(globs); } /* END if ((globs = strchr(spec,'#')) != NULL) */ +done_stage1: + + /* if job is provided, also add each of the requested resources in the job resource list */ + if (pjob != NULL && (pjob->ji_wattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET) != 0) + { + resource *jbrc = (resource *)GET_NEXT(pjob->ji_wattr[(int)JOB_ATR_resource].at_val.at_list); + + while (jbrc != NULL) + { + tlist_head head; + svrattrl *patlist; + char *buff, *tmp; + int len; + + /* only add resources that are per-proc or per-node */ + if ((jbrc->rs_defin->rs_flags & (ATR_DFLAG_SELECT_MOM | ATR_DFLAG_SELECT_PROC)) == 0) + { + jbrc = (resource *)GET_NEXT(jbrc->rs_link); + continue; + } + + /* convert resource into char* */ + CLEAR_HEAD(head); + jbrc->rs_defin->rs_encode(&jbrc->rs_value,&head,"ignored", + jbrc->rs_defin->rs_name,ATR_ENCODE_CLIENT); + patlist = (svrattrl *)GET_NEXT(head); + + if (patlist == NULL) + goto fail; + + len = strlen(patlist->al_atopl.resource); + len += strlen(patlist->al_atopl.value); + len += 2; /* '=' and '\0' */ + buff = malloc(len); + + if (buff == NULL) + goto fail; + + sprintf(buff,"%s=%s",patlist->al_atopl.resource,patlist->al_atopl.value); + + /* append to each part of the nodespec */ + tmp = nodespec_app(result, buff); + if (tmp == NULL) + goto fail; + + free(buff); + free(result); + result = tmp; + + jbrc = (resource *)GET_NEXT(jbrc->rs_link); + } + } + return result; + +fail: + free(result); + return NULL; } @@ -3443,7 +3524,7 @@ static int node_spec( exclusive = 1; /* by default, nodes (VPs) are requested exclusively */ /* expand the global reqs into the local parts */ - spec = nodespec_expand(spec,&exclusive); + spec = nodespec_expand(pjob, spec,&exclusive); if (pjob != NULL) /* store the expanded nodespec */ { @@ -4048,7 +4129,8 @@ int add_job_to_node( struct pbssubn *snp, /* I/O */ short newstate, /* I */ job *pjob, /* I */ - int exclusive) /* I */ + int exclusive, /* I */ + int first) { char *id = "add_job_to_node"; @@ -4088,7 +4170,7 @@ int add_job_to_node( jp->order = pnode->nd_order; pnode->nd_nsnfree--; /* reduce free count */ - adjust_resources_use(pnode,jp,INCR); + adjust_resources_use(pnode,jp,first,INCR); /* if no free VPs, set node state */ if (pnode->nd_nsnfree <= 0) @@ -4189,6 +4271,8 @@ int set_nodes( char ProcBMStr[MAX_BM]; + int first; + if (FailHost != NULL) FailHost[0] = '\0'; @@ -4282,6 +4366,7 @@ int set_nodes( } #endif /* GEOMETRY_REQUESTS */ + first = 1; for (snp = pnode->nd_psn;snp && pnode->nd_needed;snp = snp->next) { if (exclusive) @@ -4297,7 +4382,8 @@ int set_nodes( /* Mark subnode as being IN USE */ - add_job_to_node(pnode,snp,newstate,pjob,exclusive); + add_job_to_node(pnode,snp,newstate,pjob,exclusive,first); + first = 0; build_host_list(&hlist,snp,pnode); } /* END for (snp) */ @@ -4514,7 +4600,7 @@ int node_avail( if (pn->nd_state & INUSE_DELETED) continue; - if ((pn->nd_ntype == NTYPE_CLUSTER) && hasprop(pn, prop)) + if ((pn->nd_ntype == NTYPE_CLUSTER) && hasprop(pn, prop, node_req)) { if (pn->nd_state & (INUSE_OFFLINE | INUSE_DOWN)) ++xdown; @@ -4739,13 +4825,70 @@ find_ts_node(void) return(NULL); } /* END find_ts_node() */ +/** Adjust a node resource value + * + * @param pattr Attribute holding the resources + * @param name Name of the resource + * @param value Value by which to adjust + * @param first 1 if this the first adjustment on node, 0 if not + * @param op Operation, INCR or DECR + */ +static void adjust_resource_value(attribute *pattr, char *name, char *value, int first, enum batch_op op) + { + resource_def *defin; + resource *val; + resource decoded; + int ret; + + if (value == NULL) + return; + + defin = find_resc_def(svr_resc_def,name,svr_resc_size); + + if (defin == NULL) /* not a known resource */ + return; + + /* if this is not a per-proc or per-node resource, ignore */ + if ((defin->rs_flags & (ATR_DFLAG_SELECT_MOM | ATR_DFLAG_SELECT_PROC)) == 0) + return; + + /* if this is not the first adjustment on node and the resources is not per-proc, ignore */ + if ((defin->rs_flags & ATR_DFLAG_SELECT_PROC) == 0 && first == 0) + return; + + ret = defin->rs_decode(&decoded.rs_value,0,name,value); + + if (ret != 0) /* could not decode value */ + return; + + val = find_resc_entry(pattr,defin); + + if (val == NULL && op == INCR) + { /* if increasing the value and the resource is not yet present, add new entry */ + val = add_resource_entry(pattr,defin); + + if (val == NULL) + return; + + ret = defin->rs_set(&val->rs_value,&decoded.rs_value,SET); + } + else if (val != NULL) + { + ret = defin->rs_set(&val->rs_value,&decoded.rs_value,op); + } + } + + + + /** Adjust the resources use on a node * * @param pnode Node with the resources * @param jp Job info + * @param first Determines if this is the first adjustment for this node * @param op Operation to do (increment, decrement) */ -void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, +void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, int first, enum batch_op op) { struct prop *prop = NULL, *iter = NULL; @@ -4808,42 +4951,11 @@ void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, return; } - iter = prop; + iter = prop; /* iterating through resources in nodespec */ while (iter != NULL) { - resource_def *defin; - resource *val; - resource decoded; - int ret; - - if (iter->value != NULL) - /* it is a resource */ - if ((defin = find_resc_def(svr_resc_def,iter->name,svr_resc_size))) - /* it is a known resource */ - { - ret = defin->rs_decode(&decoded.rs_value,0,iter->name,iter->value); - if (ret != 0) - continue; /* ignore if cannot decode */ - if ((val = find_resc_entry(&pnode->attributes[1],defin))) - /* some value already present */ - { - ret = defin->rs_set(&val->rs_value,&decoded.rs_value,op); - if (ret != 0) - continue; /* ignore if cannot set */ - } - else - { - if (op == INCR) /* add new record only if increasing */ - { - if ((val = add_resource_entry(&pnode->attributes[1],defin))) - { - ret = defin->rs_set(&val->rs_value,&decoded.rs_value,SET); - if (ret != 0) - continue; /* ignore if cannot set */ - } - } - } - } + /* adjust the value */ + adjust_resource_value(&pnode->attributes[1],iter->name,iter->value,first,op); iter = iter->next; } } @@ -4866,6 +4978,7 @@ void free_nodes( struct jobinfo *jp, *prev; int i; + int first; if (LOGLEVEL >= 3) { @@ -4890,6 +5003,7 @@ void free_nodes( /* examine all subnodes in node */ + first = 1; for (np = pnode->nd_psn;np != NULL;np = np->next) { /* examine all jobs allocated to subnode */ @@ -4919,7 +5033,8 @@ void free_nodes( else prev->next = jp->next; - adjust_resources_use(pnode,jp,DECR); + adjust_resources_use(pnode,jp,first,DECR); + first = 0; free(jp); @@ -4975,7 +5090,8 @@ static void set_one_old( char *name, job *pjob, int shared, /* how used flag, either INUSE_JOB or INUSE_JOBSHARE */ - int order) + int order, + int first) { int i; @@ -5029,7 +5145,7 @@ static void set_one_old( jp->order = order; } - adjust_resources_use(pnode,jp,INCR); + adjust_resources_use(pnode,jp,first,INCR); if (--pnode->nd_nsnfree <= 0) pnode->nd_state |= shared; @@ -5088,7 +5204,7 @@ void set_old_nodes( if ((pjob->ji_wattr[(int)JOB_ATR_sched_spec].at_flags & ATR_VFLAG_SET) != 0) { free(pjob->ji_expanded_spec); - pjob->ji_expanded_spec = nodespec_expand(pjob->ji_wattr[(int)JOB_ATR_sched_spec].at_val.at_str,&excl); + pjob->ji_expanded_spec = nodespec_expand(pjob, pjob->ji_wattr[(int)JOB_ATR_sched_spec].at_val.at_str,&excl); } /* duplicate the expanded nodespec, so we can work with it */ @@ -5117,6 +5233,7 @@ void set_old_nodes( do /* for each part of the nodespec */ { char *ppn = NULL; + int ppn_count = 0; spec = ps; /* swap for the next part */ @@ -5134,7 +5251,6 @@ void set_old_nodes( ppn = strstr(spec,"ppn="); if (ppn != NULL) /* there is ppn */ { - int ppn_count; ppn+=4; /* move beyond ppn= */ ppn_count = atoi(ppn); @@ -5154,7 +5270,7 @@ void set_old_nodes( *po = '\0'; po++; } - set_one_old(old, pjob, shared, order); + set_one_old(old, pjob, shared, order, (remaining % ppn_count == 0) ? 1 : 0); remaining--; } while (remaining > 0 && po != NULL); diff --git a/src/server/req_manager.c b/src/server/req_manager.c index 434f3c6..83b181f 100644 --- a/src/server/req_manager.c +++ b/src/server/req_manager.c @@ -149,7 +149,7 @@ extern char *msg_man_uns; extern int que_purge(pbs_queue *); extern void save_characteristic(struct pbsnode *); extern int chk_characteristic(struct pbsnode *, int *); -extern int hasprop(struct pbsnode *, struct prop *); +extern int hasprop(struct pbsnode *, struct prop *, int proc_count); extern int PNodeStateToString(int, char *, int); @@ -1717,7 +1717,7 @@ void mgr_node_set( for (i = 0;i < svr_totnodes;i++, pnode = pbsndlist[i]) { - if (propnodes && !hasprop(pnode, &props)) + if (propnodes && !hasprop(pnode, &props, 1)) continue; save_characteristic(pnode); diff --git a/src/server/req_stat.c b/src/server/req_stat.c index 71048ae..4853bf3 100644 --- a/src/server/req_stat.c +++ b/src/server/req_stat.c @@ -129,7 +129,7 @@ int status_job A_((job *, struct batch_request *, svrattrl *, tlist_head *, int int status_attrib A_((svrattrl *, attribute_def *, attribute *, int, int, tlist_head *, int *, int)); extern int svr_connect A_((pbs_net_t, unsigned int, void (*)(int), enum conn_type)); extern int status_nodeattrib(svrattrl *, attribute_def *, struct pbsnode *, int, int, tlist_head *, int*); -extern int hasprop(struct pbsnode *, struct prop *); +extern int hasprop(struct pbsnode *, struct prop *, int proc_count); extern void rel_resc(job*); /* Private Data Definitions */ @@ -1232,7 +1232,7 @@ void req_stat_node( { pnode = pbsndmast[i]; - if ((type == 2) && !hasprop(pnode, &props)) + if ((type == 2) && !hasprop(pnode, &props, 1)) continue; if ((rc = status_node(pnode, preq, &preply->brp_un.brp_status)) != 0) diff --git a/src/server/resc_def_all.c b/src/server/resc_def_all.c index 2076aea..3af1f7a 100644 --- a/src/server/resc_def_all.c +++ b/src/server/resc_def_all.c @@ -170,7 +170,7 @@ resource_def svr_resc_def_const[] = comp_size, free_null, NULL_FUNC, - READ_WRITE | ATR_DFLAG_MOM | ATR_DFLAG_ALTRUN | ATR_DFLAG_RASSN, + READ_WRITE | ATR_DFLAG_MOM | ATR_DFLAG_ALTRUN | ATR_DFLAG_RASSN | ATR_DFLAG_SELECT_MOM, ATR_TYPE_SIZE }, { "pmem", @@ -190,7 +190,7 @@ resource_def svr_resc_def_const[] = comp_l, free_null, NULL_FUNC, - READ_WRITE | ATR_DFLAG_MOM | ATR_DFLAG_RMOMIG | ATR_DFLAG_RASSN, + READ_WRITE | ATR_DFLAG_MOM | ATR_DFLAG_RMOMIG | ATR_DFLAG_RASSN | ATR_DFLAG_SELECT_PROC, ATR_TYPE_LONG }, { "vmem",