Exemplo n.º 1
0
/* sort_tree_by_shares()
 */
static void
sort_tree_by_shares(struct tree_ *t)
{
    link_t *stack;
    struct tree_node_ *root;
    struct tree_node_ *n;

    stack = make_link();
    root = t->root;
    n = root->child;

znovu:
    while (n) {

        if (n->child)
            enqueue_link(stack, n);

        n = n->right;
    }

    sort_siblings(root, node_cmp);

    n = pop_link(stack);
    if (n) {
        root = n;
        n = root->child;
        goto znovu;
    }

    fin_link(stack);
    make_leafs(t);
}
Exemplo n.º 2
0
/* sort_tree_by_deviate()
 *
 */
static void
sort_tree_by_deviate(struct tree_ *t)
{
    struct tree_node_ *n;
    struct tree_node_ *n2;
    struct tree_node_ *root;
    link_t *stack;
    struct share_acct *s;
    uint64_t sum;
    uint64_t avail;

    stack = make_link();
    root = t->root;
    n = root->child;

znovu:
    n2 = n;
    sum = 0;
    while (n) {

        if (n->child)
            enqueue_link(stack, n);

        s = n->data;
        s->dsrv2 = 0;
        /* sum up the historical.
         */
        sum = sum + s->numRAN;
        n = n->right;
    }

    avail = sum;
    n = n2;
    while (n) {

        avail = avail - compute_deviate(n, sum, avail);
        assert(avail >= 0);
        n = n->right;
    }

    sort_siblings(root, node_cmp2);

    n = pop_link(stack);
    if (n) {
        root = n;
        n = n->child;
        goto znovu;
    }

    fin_link(stack);
    make_leafs(t);
}
Exemplo n.º 3
0
/*
 * Sorts the siblings by date and returns the first item in the list.
 */
static Container *sort_siblings(Container *c)
{
    Container *sibling = c;

    /* We need to sort all of our siblings' children */
    while (sibling) {
        if (sibling->child)
            sibling->child = sort_siblings(sibling->child);
        sibling = sibling->next;
    }

    /* Sort us and our siblings */
    return (Container *) mbox_sort_linked_list(c, 3, compare_siblings,
                                               NULL, NULL);
}
Exemplo n.º 4
0
/* 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;
}
Exemplo n.º 5
0
/*
 * Calculates the threading relationships for a list of messages
 */
Container *calculate_threads(apr_pool_t *p, MBOX_LIST *l)
{
    apr_hash_t *h, *rootSet, *subjectSet;
    apr_hash_index_t *hashIndex;
    MBOX_LIST *current = l;
    const apr_array_header_t *refHdr;
    apr_table_entry_t *refEnt;
    Message *m;
    Container *c, *subjectPair, *realParent, *curParent, *tmp;
    void *hashKey, *hashVal, *subjectVal;
    char *subject;
    int msgIDLen, refLen, i;
    apr_ssize_t hashLen, subjectLen;

    /* FIXME: Use APR_HASH_KEY_STRING instead?  Maybe slower. */
    h = apr_hash_make(p);

    while (current != NULL) {
        m = (Message *) current->value;
        msgIDLen = strlen(m->msgID);
        c = (Container *) apr_hash_get(h, m->msgID, msgIDLen);
        if (c) {
            c->message = m;
        }
        else {
            c = (Container *) apr_pcalloc(p, sizeof(Container));
            c->message = m;
            c->parent = NULL;
            c->child = NULL;
            c->next = NULL;
            apr_hash_set(h, m->msgID, msgIDLen, c);
        }

        realParent = NULL;

        if (m->references) {
            refHdr = apr_table_elts(m->references);
            refEnt = (apr_table_entry_t *) refHdr->elts;

            for (i = 0; i < refHdr->nelts; i++) {

                refLen = strlen(refEnt[i].key);

                curParent =
                    (Container *) apr_hash_get(h, refEnt[i].key, refLen);

                /* Create a dummy node to store the message we haven't
                 * yet seen. */
                if (!curParent) {
                    curParent =
                        (Container *) apr_pcalloc(p, sizeof(Container));
                    apr_hash_set(h, refEnt[i].key, refLen, curParent);
                }

                /* Check to make sure we are not going to create a loop
                 * by adding this parent to our list.
                 */
                if (realParent &&
                    !detect_loop(curParent, realParent) &&
                    !detect_loop(realParent, curParent)) {
                    /* Update the parent */
                    if (curParent->parent)
                        unlink_parent(curParent);

                    curParent->parent = realParent;
                    curParent->next = realParent->child;
                    realParent->child = curParent;
                }

                /* We now have a new parent */
                realParent = curParent;
            }

        }

        /* The last parent we saw is our parent UNLESS it causes a loop. */
        if (realParent && !detect_loop(c, realParent) &&
            !detect_loop(realParent, c)) {
            /* We need to unlink our parent's link to us. */
            if (c->parent)
                unlink_parent(c);

            c->parent = realParent;
            c->next = realParent->child;
            realParent->child = c;
        }

        current = current->next;
    }

    /* Find the root set */
    rootSet = apr_hash_make(p);

    for (hashIndex = apr_hash_first(p, h); hashIndex;
         hashIndex = apr_hash_next(hashIndex)) {
        apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal);
        c = (Container *) hashVal;
        if (!c->parent)
            apr_hash_set(rootSet, hashKey, hashLen, c);
    }

    /* Prune empty containers */
    for (hashIndex = apr_hash_first(p, rootSet); hashIndex;
         hashIndex = apr_hash_next(hashIndex)) {
        apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal);
        c = (Container *) hashVal;

        prune_container(c);

        if (!c->message && !c->child)
            apr_hash_set(rootSet, hashKey, hashLen, NULL);
    }

    /* Merge root set by subjects */
    subjectSet = apr_hash_make(p);

    for (hashIndex = apr_hash_first(p, rootSet); hashIndex;
         hashIndex = apr_hash_next(hashIndex)) {
        apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal);
        c = (Container *) hashVal;

        /* If we don't have a message, our child will. */
        if (!c->message)
            c = c->child;

        subject = strip_subject(p, c->message);
        subjectLen = strlen(subject);

        /* FIXME: Match what JWZ says */
        subjectVal = apr_hash_get(subjectSet, subject, subjectLen);
        if (subjectVal) {
            if (!c->message)
                apr_hash_set(subjectSet, subject, strlen(subject), hashVal);
            else {
                subjectPair = (Container *) subjectVal;
                if (!is_reply(c->message) && is_reply(subjectPair->message))
                    apr_hash_set(subjectSet, subject, strlen(subject),
                                 hashVal);
            }
        }
        else
            apr_hash_set(subjectSet, subject, strlen(subject), hashVal);
    }

    /* Subject table now populated */
    for (hashIndex = apr_hash_first(p, rootSet); hashIndex;
         hashIndex = apr_hash_next(hashIndex)) {
        apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal);
        c = (Container *) hashVal;

        /* If we don't have a message, our child will. */
        if (c->message)
            subject = strip_subject(p, c->message);
        else
            subject = strip_subject(p, c->child->message);

        subjectLen = strlen(subject);

        subjectVal = apr_hash_get(subjectSet, subject, subjectLen);
        subjectPair = (Container *) subjectVal;

        /* If we need to merge the tables */
        if (subjectPair && subjectPair != c) {
            if (!c->message || !subjectPair->message) { /* One is dummy */
                if (!c->message && !subjectPair->message)
                    join_container(subjectPair, c);
                else if (c->message && !subjectPair->message) {
                    /* It's possible that we're already a child! */
                    if (c->parent != subjectPair)
                        append_container(subjectPair, c);
                }
                else {          /* (!c->message && subjectPair->message) */

                    append_container(c, subjectPair);
                    apr_hash_set(subjectSet, subject, subjectLen, c);
                    delete_from_hash(p, rootSet, subjectPair);
                }
            }
            else {              /* Both aren't dummies */

                /* We are Reply */
                if (is_reply(c->message) && !is_reply(subjectPair->message))
                    append_container(subjectPair, c);
                else if (!is_reply(c->message) &&
                         is_reply(subjectPair->message)) {
                    append_container(c, subjectPair);
                    apr_hash_set(subjectSet, subject, subjectLen, c);
                    delete_from_hash(p, rootSet, subjectPair);
                }
                else {          /* We are both replies. */

                    c = merge_container(p, c, subjectPair);
                    apr_hash_set(subjectSet, subject, subjectLen, c);
                    delete_from_hash(p, rootSet, subjectPair);
                }
            }
        }
    }

    /* Now, we are done threading.  We want to return a sorted container
     * back to our caller.  All children of the root set need to be in
     * order and then we need to issue an ordering to the root set.
     */
    tmp = NULL;
    /* Sort siblings */
    for (hashIndex = apr_hash_first(p, subjectSet); hashIndex;
         hashIndex = apr_hash_next(hashIndex)) {
        apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal);
        c = (Container *) hashVal;

        sort_siblings(c);

        if (tmp)
            c->next = tmp;
        tmp = c;
    }

    return (Container *) mbox_sort_linked_list(tmp, 3, compare_siblings, NULL,
                                               NULL);
}