Ejemplo n.º 1
0
size_t
ipset_node_reachable_count(const struct ipset_node_cache *cache,
                           ipset_node_id node)
{
    /* Create a set to track when we've visited a given node. */
    struct cork_hash_table  *visited = cork_pointer_hash_table_new(0, 0);

    /* And a queue of nodes to check. */
    cork_array(ipset_node_id)  queue;
    cork_array_init(&queue);

    if (ipset_node_get_type(node) == IPSET_NONTERMINAL_NODE) {
        DEBUG("Adding node %u to queue", node);
        cork_array_append(&queue, node);
    }

    /* And somewhere to store the result. */
    size_t  node_count = 0;

    /* Check each node in turn. */
    while (!cork_array_is_empty(&queue)) {
        ipset_node_id  curr = cork_array_at(&queue, --queue.size);

        /* We don't have to do anything if this node is already in the
         * visited set. */
        if (cork_hash_table_get(visited, (void *) (uintptr_t) curr) == NULL) {
            DEBUG("Visiting node %u for the first time", curr);

            /* Add the node to the visited set. */
            cork_hash_table_put
                (visited, (void *) (uintptr_t) curr,
                 (void *) (uintptr_t) true, NULL, NULL, NULL);

            /* Increase the node count. */
            node_count++;

            /* And add the node's nonterminal children to the visit
             * queue. */
            struct ipset_node  *node =
                ipset_node_cache_get_nonterminal(cache, curr);

            if (ipset_node_get_type(node->low) == IPSET_NONTERMINAL_NODE) {
                DEBUG("Adding node %u to queue", node->low);
                cork_array_append(&queue, node->low);
            }

            if (ipset_node_get_type(node->high) == IPSET_NONTERMINAL_NODE) {
                DEBUG("Adding node %u to queue", node->high);
                cork_array_append(&queue, node->high);
            }
        }
    }

    /* Return the result, freeing everything before we go. */
    cork_hash_table_free(visited);
    cork_array_done(&queue);
    return node_count;
}
Ejemplo n.º 2
0
/* Retrieves the next value from the consumer's queue.  When this
 * returns c->current_id will be the ID of the next value.  You can
 * retrieve the value using vrt_queue_get. */
static int
vrt_consumer_next_raw(struct vrt_queue *q, struct vrt_consumer *c)
{
    /* We've just finished processing the current_id'th value. */
    vrt_value_id  last_consumed_id = c->current_id++;

    /* If we know there are values available that we haven't yet
     * consumed, go ahead and return one. */
    if (vrt_mod_le(c->current_id, c->last_available_id)) {
        clog_trace("<%s> Next value is %d (already available)",
                   c->name, c->current_id);
        return 0;
    }

    /* We've run out of values that we know can been processed.  Notify
     * the world how much we've processed so far. */
    clog_debug("<%s> Signal consumption of %d", c->name, last_consumed_id);
    vrt_consumer_set_cursor(c, last_consumed_id);

    /* Check to see if there are any more values that we can process. */
    if (cork_array_is_empty(&c->dependencies)) {
        bool  first = true;
        vrt_value_id  last_available_id;
        clog_debug("<%s> Wait for value %d", c->name, c->current_id);

        /* If we don't have any dependencies check the queue itself to see how
         * many values have been published. */
        last_available_id = vrt_queue_get_cursor(q);
        while (vrt_mod_le(last_available_id, last_consumed_id)) {
            clog_trace("<%s> Last available value is %d (wait)",
                       c->name, last_available_id);
            c->yield_count++;
            rii_check(vrt_yield_strategy_yield
                      (c->yield, first, q->name, c->name));
            first = false;
            last_available_id = vrt_queue_get_cursor(q);
        }
        c->last_available_id = last_available_id;
        clog_debug("<%s> Last available value is %d",
                   c->name, last_available_id);
    } else {
        bool  first = true;
        vrt_value_id  last_available_id;
        clog_debug("<%s> Wait for value %d from dependencies",
                   c->name, c->current_id);

        /* If there are dependencies we can only process what they've *all*
         * finished processing. */
        last_available_id = vrt_consumer_find_last_dependent_id(c);
        while (vrt_mod_le(last_available_id, last_consumed_id)) {
            clog_trace("<%s> Last available value is %d (wait)",
                       c->name, last_available_id);
            c->yield_count++;
            rii_check(vrt_yield_strategy_yield
                      (c->yield, first, q->name, c->name));
            first = false;
            last_available_id = vrt_consumer_find_last_dependent_id(c);
        }
        c->last_available_id = last_available_id;
        clog_debug("<%s> Last available value is %d",
                   c->name, last_available_id);
    }

    c->batch_count++;

    /* Once we fall through to here, we know that there are additional
     * values that we can process. */
    clog_trace("<%s> Next value is %d", c->name, c->current_id);
    return 0;
}