/* parse_user_shares() * * parse user_shares[[g, 1] [e,1]] */ static link_t * parse_user_shares(const char *user_shares) { link_t *l; char *p; char *u; int cc; int n; struct share_acct *sacct; uint32_t sum_shares; linkiter_t iter; u = strdup(user_shares); assert(u); p = strchr(u, '['); *p++ = 0; tokenize(p); l = make_link(); sum_shares = 0; while (1 ) { char name[128]; uint32_t shares; cc = sscanf(p, "%s%u%n", name, &shares, &n); if (cc == EOF) break; if (cc != 2) goto bail; p = p + n; sacct = make_sacct(name, shares); assert(sacct); sum_shares = sum_shares + sacct->shares; enqueue_link(l, sacct); } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { sacct->dshares = (double)sacct->shares/(double)sum_shares; } _free_(u); return l; bail: _free_(u); traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) free_sacct(sacct); fin_link(l); return NULL; }
/* sshare_make_tree() * In this function we match the user_shares as configured * in the queue file with the groups configured in lsb.users. * The fairshare configuration in the queues can be such * that they don't match for example: * * FAIRSHARE = USER_SHARES[[crock ,2] [zebra, 1]] * FAIRSHARE = USER_SHARES[[all, 1]] * * in these cases the shares are specified for users * directly and no groups are involved. */ struct tree_ *sshare_make_tree(const char *user_shares, uint32_t num_grp, struct group_acct *grp) { struct tree_ *t; link_t *l; link_t *stack; linkiter_t iter; struct share_acct *sacct; struct tree_node_ *n; struct tree_node_ *root; n = NULL; stack = make_link(); t = tree_init(""); /* root summarizes all the tree counters */ t->root->data = make_sacct("/", 1); root = NULL; /* First parse the user shares and make * the first level of the tree */ l = parse_user_shares(user_shares); z: if (root) l = parse_group_member(n->name, num_grp, grp); else root = t->root; if (l == NULL) { free_sacct(t->root->data); fin_link(stack); tree_free(t, free_sacct); return NULL; } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { n = calloc(1, sizeof(struct tree_node_)); /* dup() the name as later we free both * the tree node and the share account */ n->name = strdup(sacct->name); n = tree_insert_node(root, n); enqueue_link(stack, n); n->data = sacct; } /* Sort by shares so the tree * is always sorted by share * priority */ sort_siblings(root, node_cmp); fin_link(l); n = pop_link(stack); if (n) { root = n; goto z; } fin_link(stack); n = t->root; while ((n = tree_next_node(n))) { char buf[BUFSIZ]; /* Create the hash table of nodes and their * immediate parent. */ sacct = n->data; if (n->child == NULL) { /* all and default are synonyms as they * both indicate a user that is not explicitly * defined. */ if (strcasecmp(sacct->name, "all") == 0 || strcasecmp(sacct->name, "default") == 0) { sacct->options |= SACCT_USER_ALL; } sacct->options |= SACCT_USER; sprintf(buf, "%s/%s", n->parent->name, n->name); hash_install(t->node_tab, buf, n, NULL); } else { sacct->options |= SACCT_GROUP; } sprintf(buf, "%s", n->name); hash_install(t->node_tab, buf, n, NULL); print_node(n, t); } traverse_init(t->leafs, &iter); while ((n = traverse_link(&iter))) print_node(n, t); /* Fairshare tree is built and sorted * by decreasing shares, the scheduler * algorithm will fill it up with * slots from now on. */ tree_walk2(t, print_node); sort_tree_by_shares(t); return t; }
/* parseUsage() */ static int parseUsage(char *usageReq, struct resVal *resVal, struct lsInfo *lsInfo) { int i; int m; int entry; float value; char *token; link_t *link; linkiter_t iter; struct _rusage_ *r; char *s; int *rusage_bit_map; float *val; char *usageReq2; char *s2; if ((i = strlen(usageReq)) == 0) return PARSE_OK; for (m = 0; m < i; m++) if (usageReq[m] != ' ') break; if (m == i) return PARSE_OK; s2 = usageReq2 = strip_spaces(usageReq); resVal->rl = make_link(); link = get_rusage_entries(usageReq2); i = 0; traverse_init(link, &iter); while ((s = traverse_link(&iter))) { /* Allocate for each element of the link */ rusage_bit_map = calloc(GET_INTNUM(lsInfo->nRes), sizeof(int)); val = calloc(lsInfo->nRes, sizeof(float)); resVal->genClass = 0; while ((token = getNextToken(&s)) != NULL) { if (token[0] == '-') token++; entry = getKeyEntry(token); if (entry > 0) { if (entry != KEY_DURATION && entry != KEY_DECAY) goto pryc; if (s[0] == '=') { int returnValue; if (entry == KEY_DURATION) returnValue = getTimeVal(&s, &value); else returnValue = getVal(&s, &value); if (returnValue < 0 || value < 0.0) return PARSE_BAD_VAL; if (entry == KEY_DURATION) resVal->duration = value; else resVal->decay = value; continue; } } entry = getResEntry(token); if (entry < 0) goto pryc; if (!(lsInfo->resTable[entry].flags & RESF_DYNAMIC) && (lsInfo->resTable[entry].valueType != LS_NUMERIC)) { if (s[0] == '=') { if (getVal(&s, &value) < 0 || value < 0.0) goto pryc; } continue; } if (entry < MAXSRES) resVal->genClass |= 1 << entry; SET_BIT(entry, rusage_bit_map); if (s[0] == '=') { if (getVal(&s, &value) < 0 || value < 0.0) goto pryc; val[entry] = value; } } /* Save the current rusage block */ r = calloc(1, sizeof(struct _rusage_)); r->bitmap = rusage_bit_map; r->val = val; enqueue_link(resVal->rl, r); if (i == 0) { /* The entry 0 is both in the link and * in the resVal. The default values * were allocated in setDefaults() */ _free_(resVal->rusage_bit_map); _free_(resVal->val); /* Copy the values as later we free them separately */ resVal->rusage_bit_map = calloc(GET_INTNUM(lsInfo->nRes), sizeof(int)); memcpy(resVal->rusage_bit_map, rusage_bit_map, GET_INTNUM(lsInfo->nRes) * sizeof(int)); resVal->val = calloc(lsInfo->nRes, sizeof(float)); memcpy(resVal->val, r->val, lsInfo->nRes * sizeof(float)); } ++i; } /* while (s = traverse_link()) */ resVal->options |= PR_RUSAGE; while ((s = pop_link(link))) _free_(s); fin_link(link); _free_(s2); return PARSE_OK; pryc: _free_(rusage_bit_map); _free_(val); while ((s = pop_link(link))) _free_(s); fin_link(link); while ((r = pop_link(resVal->rl))) { _free_(r->bitmap); _free_(r->val); _free_(r); } fin_link(resVal->rl); resVal->rl = NULL; _free_(s2); return PARSE_BAD_NAME; }
/* parse_group_member() */ static link_t * parse_group_member(const char *gname, uint32_t num, struct group_acct *grps) { link_t *l; linkiter_t iter; struct group_acct *g; int cc; char *w; char *p; uint32_t sum; struct share_acct *sacct; l = make_link(); g = NULL; for (cc = 0; cc < num; cc++) { /* Match the group name and the group * must have shares. */ if (strcmp(gname, grps[cc].group) == 0 && grps[cc].user_shares) { g = calloc(1, sizeof(struct group_acct)); assert(g); g->group = strdup(grps[cc].group); g->memberList = strdup(grps[cc].memberList); g->user_shares = strdup(grps[cc].user_shares); tokenize(g->user_shares); break; } } /* gudness leaf member * caller will free the link */ if (g == NULL) return l; p = g->memberList; sum = 0; while ((w = get_next_word(&p))) { sacct = get_sacct(w, g->user_shares); if (sacct == NULL) { while ((sacct = pop_link(l))) free_sacct(sacct); fin_link(l); return NULL; } sum = sum + sacct->shares; enqueue_link(l, sacct); } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { sacct->dshares = (double)sacct->shares/(double)sum; } _free_(g->group); _free_(g->memberList); _free_(g->user_shares); _free_(g); return l; }