/* Calculate fairshare for each child then sort children by fairshare value * (level_fs). Once they are sorted, operate on each child in sorted order. * This portion of the tree is now sorted and users are given a fairshare value * based on the order they are operated on. The basic equation is * (rank / g_user_assoc_count), though ties are allowed. The rank is decremented * for each user that is encountered. */ static void _calc_tree_fs(slurmdb_assoc_rec_t** siblings, uint16_t assoc_level, uint32_t *rank, uint32_t *i, bool account_tied) { slurmdb_assoc_rec_t *assoc = NULL; long double prev_level_fs = (long double) NO_VAL; bool tied = false; size_t ndx; /* Calculate level_fs for each child */ for (ndx = 0; (assoc = siblings[ndx]); ndx++) _calc_assoc_fs(assoc); /* Sort children by level_fs */ qsort(siblings, ndx, sizeof(slurmdb_assoc_rec_t *), _cmp_level_fs); /* Iterate through children in sorted order. If it's a user, calculate * fs_factor, otherwise recurse. */ for (ndx = 0; (assoc = siblings[ndx]); ndx++) { if (account_tied) { tied = true; account_tied = false; } else { tied = prev_level_fs == assoc->usage->level_fs; } if (priority_debug) _ft_debug(assoc, assoc_level, tied); if (assoc->user) { if (!tied) *rank = *i; /* Set the final fairshare factor for this user */ assoc->usage->fs_factor = *rank / (double) g_user_assoc_count; (*i)--; } else { slurmdb_assoc_rec_t** children; size_t merge_count = _count_tied_accounts(siblings, ndx); /* Merging does not affect child level_fs calculations * since the necessary information is stored on each * assoc's usage struct */ children = _merge_accounts(siblings, ndx, ndx + merge_count, assoc_level); _calc_tree_fs(children, assoc_level + 1, rank, i, tied); /* Skip over any merged accounts */ ndx += merge_count; xfree(children); } prev_level_fs = assoc->usage->level_fs; } }
/* Calculate fairshare for each child then sort children by fairshare value * (level_fs). Once they are sorted, operate on each child in sorted order. * This portion of the tree is now sorted and users are given a fairshare value * based on the order they are operated on. The basic equation is * (rank / g_user_assoc_count), though ties are allowed. The rank is * decremented for each user that is encountered except when ties occur. * * Tie Handling Rules: * 1) Sibling users with the same level_fs receive the same rank * 2) Sibling accounts with the same level_fs have their children lists * merged before sorting * 3) A user with the same level_fs as a sibling account will receive * the same rank as the account's highest ranked user * * IN siblings - array of siblings * IN assoc_level - depth in the tree (root is 0) * IN/OUT rank - current user ranking, starting at g_user_assoc_count * IN/OUT rnt - rank, no ties (what rank would be if no tie exists) * IN account_tied - is this account tied with the previous user */ static void _calc_tree_fs(slurmdb_assoc_rec_t** siblings, uint16_t assoc_level, uint32_t *rank, uint32_t *rnt, bool account_tied) { slurmdb_assoc_rec_t *assoc = NULL; long double prev_level_fs = (long double) NO_VAL; bool tied = false; size_t i; /* Calculate level_fs for each child */ for (i = 0; (assoc = siblings[i]); i++) _calc_assoc_fs(assoc); /* Sort children by level_fs */ qsort(siblings, i, sizeof(slurmdb_assoc_rec_t *), _cmp_level_fs); /* Iterate through children in sorted order. If it's a user, calculate * fs_factor, otherwise recurse. */ for (i = 0; (assoc = siblings[i]); i++) { /* tied is used while iterating across siblings. * account_tied preserves ties while recursing */ if (i == 0 && account_tied) { /* The parent was tied so this level starts out tied */ tied = true; } else { tied = prev_level_fs == assoc->usage->level_fs; } if (priority_debug) _ft_debug(assoc, assoc_level, tied); /* If user, set their final fairshare factor and * handle ranking. * If account, merge any tied accounts then recurse with the * merged children array. */ if (assoc->user) { if (!tied) *rank = *rnt; assoc->usage->fs_factor = *rank / (double) g_user_assoc_count; (*rnt)--; } else { slurmdb_assoc_rec_t** children; size_t merge_count = _count_tied_accounts(siblings, i); /* Merging does not affect child level_fs calculations * since the necessary information is stored on each * assoc's usage struct */ children = _merge_accounts(siblings, i, i + merge_count, assoc_level); _calc_tree_fs(children, assoc_level+1, rank, rnt, tied); /* Skip over any merged accounts */ i += merge_count; xfree(children); } prev_level_fs = assoc->usage->level_fs; } }