/*
 * We dump as many entries from center as possible into left, then the rest
 * in right, then rebalance2.  This wastes some cpu, but I want something
 * simple atm.
 */
static void delete_center_node(struct dm_btree_info *info, struct btree_node *parent,
			       struct child *l, struct child *c, struct child *r,
			       struct btree_node *left, struct btree_node *center, struct btree_node *right,
			       uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
{
	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
	unsigned shift = min(max_entries - nr_left, nr_center);

	BUG_ON(nr_left + shift > max_entries);
	node_copy(left, center, -shift);
	left->header.nr_entries = cpu_to_le32(nr_left + shift);

	if (shift != nr_center) {
		shift = nr_center - shift;
		BUG_ON((nr_right + shift) > max_entries);
		node_shift(right, shift);
		node_copy(center, right, shift);
		right->header.nr_entries = cpu_to_le32(nr_right + shift);
	}
	*key_ptr(parent, r->index) = right->keys[0];

	delete_at(parent, c->index);
	r->index--;

	dm_tm_dec(info->tm, dm_block_location(c->block));
	__rebalance2(info, parent, l, r);
}
static void shift(struct btree_node *left, struct btree_node *right, int count)
{
	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
	uint32_t r_max_entries = le32_to_cpu(right->header.max_entries);

	BUG_ON(max_entries != r_max_entries);
	BUG_ON(nr_left - count > max_entries);
	BUG_ON(nr_right + count > max_entries);

	if (!count)
		return;

	if (count > 0) {
		node_shift(right, count);
		node_copy(left, right, count);
	} else {
		node_copy(left, right, count);
		node_shift(right, count);
	}

	left->header.nr_entries = cpu_to_le32(nr_left - count);
	right->header.nr_entries = cpu_to_le32(nr_right + count);
}
Example #3
0
/* any node in list1 or list2 and not in the other gets a score of -INFINITY */
void
node_list_exclude(GHashTable * hash, GListPtr list, gboolean merge_scores)
{
    GHashTable *result = hash;
    node_t *other_node = NULL;
    GListPtr gIter = list;

    GHashTableIter iter;
    node_t *node = NULL;

    g_hash_table_iter_init(&iter, hash);
    while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {

        other_node = pe_find_node_id(list, node->details->id);
        if (other_node == NULL) {
            node->weight = -INFINITY;
        } else if (merge_scores) {
            node->weight = merge_weights(node->weight, other_node->weight);
        }
    }

    for (; gIter != NULL; gIter = gIter->next) {
        node_t *node = (node_t *) gIter->data;

        other_node = pe_hash_table_lookup(result, node->details->id);

        if (other_node == NULL) {
            node_t *new_node = node_copy(node);

            new_node->weight = -INFINITY;
            g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
        }
    }
}
Example #4
0
GListPtr
node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
{
    GListPtr result = NULL;
    GListPtr gIter = list1;

    for (; gIter != NULL; gIter = gIter->next) {
        node_t *new_node = NULL;
        node_t *this_node = (node_t *) gIter->data;

        if (filter && this_node->weight < 0) {
            continue;
        }

        new_node = node_copy(this_node);
        if (reset) {
            new_node->weight = 0;
        }
        if (new_node != NULL) {
            result = g_list_prepend(result, new_node);
        }
    }

    return result;
}
static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
			 struct child *l, struct child *r)
{
	struct btree_node *left = l->n;
	struct btree_node *right = r->n;
	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
	unsigned threshold = 2 * merge_threshold(left) + 1;

	if (nr_left + nr_right < threshold) {
		/*
		 * Merge
		 */
		node_copy(left, right, -nr_right);
		left->header.nr_entries = cpu_to_le32(nr_left + nr_right);
		delete_at(parent, r->index);

		/*
		 * We need to decrement the right block, but not it's
		 * children, since they're still referenced by left.
		 */
		dm_tm_dec(info->tm, dm_block_location(r->block));
	} else {
		/*
		 * Rebalance.
		 */
		unsigned target_left = (nr_left + nr_right) / 2;
		shift(left, right, nr_left - target_left);
		*key_ptr(parent, r->index) = right->keys[0];
	}
}
Example #6
0
static int
node_copy_and_insert (splay_tree_node node, void *base)
{
  int n = mpz_get_si (((gfc_constructor*)node->value)->offset);
  gfc_constructor_insert ((gfc_constructor_base*)base,
			  node_copy (node, base), n);
  return 0;
}
/** Creates a deep copy of a TreeNode object starting from the input pointer.  Recursion is used to cycle through all the left and right children to set them in the new TreeNode object.
 @param copy is a const pointer to the TreeNode object being copied
 @returns a pointer to the TreeNode object with all left and right children copied that was created
 */
TreeNode* BinarySearchTree::node_copy(const TreeNode* copy) {
    //if input is nullptr cannot set left and right children and instead returns nullptr
    if(copy == nullptr) {
        return nullptr;
    }
    TreeNode* new_node = nullptr;
    //try to allocate heap memory
    try {
        new_node = new TreeNode;
    }
    //if cannot allocate heap memory, print out error statement and set pointer to nullptr
    catch (std::exception& e) {
        std::cerr << "BinarySearchTree::node_copy(const TreeNode* copy) failed to allocate heap memory." << std::endl;
        new_node = nullptr;
    }
    new_node->data = copy->data;
    //recursively calls the node_copy function on the left and right children
    new_node->left = node_copy(copy->left);
    new_node->right = node_copy(copy->right);
    return new_node;
}
Example #8
0
/**
 *	Union two linked list
 */
Node *node_union(Node* first, Node* second) {
	if (first == NULL) {
		return node_copy(second);
	}

	if (second == NULL) {
		return node_copy(first);
	}

	Node *node_result = node_copy(first);

	Node *temp = second;
	while (temp) {
		if (false == node_contain(node_result, temp->data)) {
			node_insert_last(&node_result, temp->data);
		}

		temp = temp->next;
	}

	return node_result;
}
Example #9
0
static rstatus_t
gossip_msg_to_core(struct server_pool *sp, struct node *node, void *cb)
{
	struct ring_msg *msg = create_ring_msg();
	struct node *rnode = (struct node *) array_get(&msg->nodes, 0);
	node_copy(node, rnode);

	msg->cb = cb;
	msg->sp = sp;
	CBUF_Push(C2G_OutQ, msg);

	return DN_OK;
}
Example #10
0
GHashTable *
node_hash_from_list(GListPtr list)
{
    GListPtr gIter = list;
    GHashTable *result = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);

    for (; gIter != NULL; gIter = gIter->next) {
        node_t *node = (node_t *) gIter->data;
        node_t *n = node_copy(node);

        g_hash_table_insert(result, (gpointer) n->details->id, n);
    }

    return result;
}
Example #11
0
void individual_copy(
        const individual_s * const in,
        individual_s * const out )
{
    if( (in == NULL) || (out == NULL) )
    {
        fprintf( stderr, "bad param in individual_copy" );
        graceful_exit( EXIT_FAILURE );
    }

    out->tree_root_node = node_alloc();

    node_copy( in->tree_root_node, out->tree_root_node, NULL );

    out->tree_node_count = in->tree_node_count;
    out->fitness = in->fitness;
    out->tree_terminal_count = in->tree_terminal_count;
    out->tree_nonterminal_count = in->tree_nonterminal_count;
}
Example #12
0
void individual_crossover(
        individual_s * const individual_a,
        individual_s * const individual_b )
{
    if( (individual_a == NULL) || (individual_b == NULL) )
    {
        fprintf( stderr, "bad parameter in individual_crossover\n" );
        graceful_exit( EXIT_FAILURE );
    }

    node_s *temp = NULL;

    temp = node_alloc();

    node_s *crossover_node_1 = NULL;
    node_s *crossover_node_2 = NULL;

    unsigned long step_range = 0;

    GLOBAL_LAST_STEP = 0;
    GLOBAL_STEP_COUNT = 0;

    step_range = individual_a->tree_terminal_count - 1;

    if( random_unsigned_long( 100 ) < 90 )
    {
        GLOBAL_LAST_STEP
                = (int)random_unsigned_long_in_range( 2, step_range );

        node_walk_nonterminals( individual_a->tree_root_node, &crossover_node_1 );
    }
    else
    {
        GLOBAL_LAST_STEP
                = (int)random_unsigned_long_in_range( 2, step_range );

        node_walk_terminals( individual_a->tree_root_node, &crossover_node_1 );
    }

    GLOBAL_STEP_COUNT = 0;

    step_range = individual_b->tree_nonterminal_count - 1;

    if( random_unsigned_long( 100 ) < 90 )
    {
        GLOBAL_LAST_STEP
                = (int)random_unsigned_long_in_range( 2, step_range );

        node_walk_nonterminals( individual_b->tree_root_node, &crossover_node_2 );
    }
    else
    {
        GLOBAL_LAST_STEP
                = (int)random_unsigned_long_in_range( 2, step_range );

        node_walk_terminals( individual_b->tree_root_node, &crossover_node_2 );
    }

    if( crossover_node_1 == NULL )
    {
        fprintf( stderr,
                "bad crossover_node_1 pointer in individual_crossover\n" );
        graceful_exit( EXIT_FAILURE );
    }

    node_copy( crossover_node_1, temp, crossover_node_1->parent );

    if( crossover_node_2 == NULL )
    {
        fprintf( stderr, "bad "
                "crossover_node_2 pointer in individual_crossover\n" );
        graceful_exit( EXIT_FAILURE );
    }

    node_copy( crossover_node_2, crossover_node_1, crossover_node_2->parent );

    node_copy( temp, crossover_node_2, temp->parent );

    crossover_node_1 = NULL;
    crossover_node_2 = NULL;

    node_free( &temp );
}
Example #13
0
action_t *
custom_action(resource_t * rsc, char *key, const char *task,
              node_t * on_node, gboolean optional, gboolean save_action,
              pe_working_set_t * data_set)
{
    action_t *action = NULL;
    GListPtr possible_matches = NULL;

    CRM_CHECK(key != NULL, return NULL);
    CRM_CHECK(task != NULL, return NULL);

    if (save_action && rsc != NULL) {
        possible_matches = find_actions(rsc->actions, key, on_node);
    }

    if (possible_matches != NULL) {
        if (g_list_length(possible_matches) > 1) {
            pe_warn("Action %s for %s on %s exists %d times",
                    task, rsc ? rsc->id : "<NULL>",
                    on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
        }

        action = g_list_nth_data(possible_matches, 0);
        crm_trace("Found existing action (%d) %s for %s on %s",
                  action->id, task, rsc ? rsc->id : "<NULL>",
                  on_node ? on_node->details->uname : "<NULL>");
        g_list_free(possible_matches);
    }

    if (action == NULL) {
        if (save_action) {
            crm_trace("Creating%s action %d: %s for %s on %s",
                      optional ? "" : " manditory", data_set->action_id, key,
                      rsc ? rsc->id : "<NULL>", on_node ? on_node->details->uname : "<NULL>");
        }

        action = calloc(1, sizeof(action_t));
        if (save_action) {
            action->id = data_set->action_id++;
        } else {
            action->id = 0;
        }
        action->rsc = rsc;
        CRM_ASSERT(task != NULL);
        action->task = strdup(task);
        if (on_node) {
            action->node = node_copy(on_node);
        }
        action->uuid = strdup(key);

        pe_set_action_bit(action, pe_action_failure_is_fatal);
        pe_set_action_bit(action, pe_action_runnable);
        if (optional) {
            pe_set_action_bit(action, pe_action_optional);
        } else {
            pe_clear_action_bit(action, pe_action_optional);
        }

/*
  Implied by calloc()...
  action->actions_before   = NULL;
  action->actions_after    = NULL;
		
  action->pseudo     = FALSE;
  action->dumped     = FALSE;
  action->processed  = FALSE;
  action->seen_count = 0;
*/

        action->extra = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);

        action->meta = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);

        if (save_action) {
            data_set->actions = g_list_prepend(data_set->actions, action);
        }

        if (rsc != NULL) {
            action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);

            unpack_operation(action, action->op_entry, data_set);

            if (save_action) {
                rsc->actions = g_list_prepend(rsc->actions, action);
            }
        }

        if (save_action) {
            crm_trace("Action %d created", action->id);
        }
    }

    if (optional == FALSE) {
        crm_trace("Action %d (%s) marked manditory", action->id, action->uuid);
        pe_clear_action_bit(action, pe_action_optional);
    }

    if (rsc != NULL) {
        enum action_tasks a_task = text2task(action->task);
        int warn_level = LOG_DEBUG_3;

        if (save_action) {
            warn_level = LOG_WARNING;
        }

        if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
            && action->node != NULL && action->op_entry != NULL) {
            pe_set_action_bit(action, pe_action_have_node_attrs);
            unpack_instance_attributes(data_set->input, action->op_entry, XML_TAG_ATTR_SETS,
                                       action->node->details->attrs,
                                       action->extra, NULL, FALSE, data_set->now);
        }

        if (is_set(action->flags, pe_action_pseudo)) {
            /* leave untouched */

        } else if (action->node == NULL) {
            pe_clear_action_bit(action, pe_action_runnable);

        } else if (is_not_set(rsc->flags, pe_rsc_managed)
                   && g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL) == NULL) {
            crm_debug("Action %s (unmanaged)", action->uuid);
            pe_set_action_bit(action, pe_action_optional);
/*   			action->runnable = FALSE; */

        } else if (action->node->details->online == FALSE) {
            pe_clear_action_bit(action, pe_action_runnable);
            do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
                       action->uuid, action->node->details->uname);
            if (is_set(action->rsc->flags, pe_rsc_managed)
                && save_action && a_task == stop_rsc) {
                do_crm_log(warn_level, "Marking node %s unclean", action->node->details->uname);
                action->node->details->unclean = TRUE;
            }

        } else if (action->node->details->pending) {
            pe_clear_action_bit(action, pe_action_runnable);
            do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
                       action->uuid, action->node->details->uname);

        } else if (action->needs == rsc_req_nothing) {
            crm_trace("Action %s doesnt require anything", action->uuid);
            pe_set_action_bit(action, pe_action_runnable);
#if 0
            /*
             * No point checking this
             * - if we dont have quorum we cant stonith anyway
             */
        } else if (action->needs == rsc_req_stonith) {
            crm_trace("Action %s requires only stonith", action->uuid);
            action->runnable = TRUE;
#endif
        } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
                   && data_set->no_quorum_policy == no_quorum_stop) {
            pe_clear_action_bit(action, pe_action_runnable);
            crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);

        } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
                   && data_set->no_quorum_policy == no_quorum_freeze) {
            crm_trace("Check resource is already active");
            if (rsc->fns->active(rsc, TRUE) == FALSE) {
                pe_clear_action_bit(action, pe_action_runnable);
                crm_debug("%s\t%s (cancelled : quorum freeze)",
                          action->node->details->uname, action->uuid);
            }

        } else {
            crm_trace("Action %s is runnable", action->uuid);
            pe_set_action_bit(action, pe_action_runnable);
        }

        if (save_action) {
            switch (a_task) {
                case stop_rsc:
                    set_bit(rsc->flags, pe_rsc_stopping);
                    break;
                case start_rsc:
                    clear_bit(rsc->flags, pe_rsc_starting);
                    if (is_set(action->flags, pe_action_runnable)) {
                        set_bit(rsc->flags, pe_rsc_starting);
                    }
                    break;
                default:
                    break;
            }
        }
    }

    free(key);
    return action;
}
/** Overloaded the copy constructor to make a deep copy of the BinarySearchTree object. The constructor uses the copy_node function which sets the left and right children and  the recursive set_parent function to update the parent node pointers.
 @param copy is a const reference of the BinarySearchTree object that is being copied
 */
BinarySearchTree::BinarySearchTree(const BinarySearchTree& copy) {
    root = node_copy(copy.root);
    root->node_parent = nullptr;
    set_parent(root);
}
Example #15
0
gint
sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
{
    int rc = 0;
    node_t *node1 = NULL;
    node_t *node2 = NULL;
    node_t *current_node1 = NULL;
    node_t *current_node2 = NULL;
    unsigned int nnodes1 = 0;
    unsigned int nnodes2 = 0;

    gboolean can1 = TRUE;
    gboolean can2 = TRUE;

    const resource_t *resource1 = (const resource_t *)a;
    const resource_t *resource2 = (const resource_t *)b;

    CRM_ASSERT(resource1 != NULL);
    CRM_ASSERT(resource2 != NULL);

    /* allocation order:
     *  - active instances
     *  - instances running on nodes with the least copies
     *  - active instances on nodes that can't support them or are to be fenced
     *  - failed instances
     *  - inactive instances
     */

    current_node1 = pe__find_active_on(resource1, &nnodes1, NULL);
    current_node2 = pe__find_active_on(resource2, &nnodes2, NULL);

    if (nnodes1 && nnodes2) {
        if (nnodes1 < nnodes2) {
            crm_trace("%s < %s: running_on", resource1->id, resource2->id);
            return -1;

        } else if (nnodes1 > nnodes2) {
            crm_trace("%s > %s: running_on", resource1->id, resource2->id);
            return 1;
        }
    }

    node1 = current_node1;
    node2 = current_node2;
    if (node1) {
        node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id);

        if (match == NULL || match->weight < 0) {
            crm_trace("%s: current location is unavailable", resource1->id);
            node1 = NULL;
            can1 = FALSE;
        }
    }

    if (node2) {
        node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id);

        if (match == NULL || match->weight < 0) {
            crm_trace("%s: current location is unavailable", resource2->id);
            node2 = NULL;
            can2 = FALSE;
        }
    }

    if (can1 != can2) {
        if (can1) {
            crm_trace("%s < %s: availability of current location", resource1->id, resource2->id);
            return -1;
        }
        crm_trace("%s > %s: availability of current location", resource1->id, resource2->id);
        return 1;
    }

    if (resource1->priority < resource2->priority) {
        crm_trace("%s < %s: priority", resource1->id, resource2->id);
        return 1;

    } else if (resource1->priority > resource2->priority) {
        crm_trace("%s > %s: priority", resource1->id, resource2->id);
        return -1;
    }

    if (node1 == NULL && node2 == NULL) {
        crm_trace("%s == %s: not active", resource1->id, resource2->id);
        return 0;
    }

    if (node1 != node2) {
        if (node1 == NULL) {
            crm_trace("%s > %s: active", resource1->id, resource2->id);
            return 1;
        } else if (node2 == NULL) {
            crm_trace("%s < %s: active", resource1->id, resource2->id);
            return -1;
        }
    }

    can1 = can_run_resources(node1);
    can2 = can_run_resources(node2);
    if (can1 != can2) {
        if (can1) {
            crm_trace("%s < %s: can", resource1->id, resource2->id);
            return -1;
        }
        crm_trace("%s > %s: can", resource1->id, resource2->id);
        return 1;
    }

    node1 = parent_node_instance(resource1, node1);
    node2 = parent_node_instance(resource2, node2);
    if (node1 != NULL && node2 == NULL) {
        crm_trace("%s < %s: not allowed", resource1->id, resource2->id);
        return -1;
    } else if (node1 == NULL && node2 != NULL) {
        crm_trace("%s > %s: not allowed", resource1->id, resource2->id);
        return 1;
    }

    if (node1 == NULL || node2 == NULL) {
        crm_trace("%s == %s: not allowed", resource1->id, resource2->id);
        return 0;
    }

    if (node1->count < node2->count) {
        crm_trace("%s < %s: count", resource1->id, resource2->id);
        return -1;

    } else if (node1->count > node2->count) {
        crm_trace("%s > %s: count", resource1->id, resource2->id);
        return 1;
    }

    can1 = did_fail(resource1);
    can2 = did_fail(resource2);
    if (can1 != can2) {
        if (can1) {
            crm_trace("%s > %s: failed", resource1->id, resource2->id);
            return 1;
        }
        crm_trace("%s < %s: failed", resource1->id, resource2->id);
        return -1;
    }

    if (node1 && node2) {
        int lpc = 0;
        int max = 0;
        node_t *n = NULL;
        GListPtr gIter = NULL;
        GListPtr list1 = NULL;
        GListPtr list2 = NULL;
        GHashTable *hash1 =
            g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free);
        GHashTable *hash2 =
            g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free);

        n = node_copy(current_node1);
        g_hash_table_insert(hash1, (gpointer) n->details->id, n);

        n = node_copy(current_node2);
        g_hash_table_insert(hash2, (gpointer) n->details->id, n);

        if(resource1->parent) {
            for (gIter = resource1->parent->rsc_cons; gIter; gIter = gIter->next) {
                rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;

                crm_trace("Applying %s to %s", constraint->id, resource1->id);

                hash1 = native_merge_weights(constraint->rsc_rh, resource1->id, hash1,
                                             constraint->node_attribute,
                                             (float)constraint->score / INFINITY, 0);
            }

            for (gIter = resource1->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
                rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;

                crm_trace("Applying %s to %s", constraint->id, resource1->id);

                hash1 = native_merge_weights(constraint->rsc_lh, resource1->id, hash1,
                                             constraint->node_attribute,
                                             (float)constraint->score / INFINITY, pe_weights_positive);
            }
        }

        if(resource2->parent) {
            for (gIter = resource2->parent->rsc_cons; gIter; gIter = gIter->next) {
                rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;

                crm_trace("Applying %s to %s", constraint->id, resource2->id);

                hash2 = native_merge_weights(constraint->rsc_rh, resource2->id, hash2,
                                             constraint->node_attribute,
                                             (float)constraint->score / INFINITY, 0);
            }

            for (gIter = resource2->parent->rsc_cons_lhs; gIter; gIter = gIter->next) {
                rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;

                crm_trace("Applying %s to %s", constraint->id, resource2->id);

                hash2 = native_merge_weights(constraint->rsc_lh, resource2->id, hash2,
                                             constraint->node_attribute,
                                             (float)constraint->score / INFINITY, pe_weights_positive);
            }
        }

        /* Current location score */
        node1 = g_hash_table_lookup(hash1, current_node1->details->id);
        node2 = g_hash_table_lookup(hash2, current_node2->details->id);

        if (node1->weight < node2->weight) {
            if (node1->weight < 0) {
                crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
                rc = -1;
                goto out;

            } else {
                crm_trace("%s < %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
                rc = 1;
                goto out;
            }

        } else if (node1->weight > node2->weight) {
            crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
            rc = -1;
            goto out;
        }

        /* All location scores */
        list1 = g_hash_table_get_values(hash1);
        list2 = g_hash_table_get_values(hash2);

        list1 = sort_nodes_by_weight(list1, current_node1, data_set);
        list2 = sort_nodes_by_weight(list2, current_node2, data_set);
        max = g_list_length(list1);
        if (max < g_list_length(list2)) {
            max = g_list_length(list2);
        }

        for (; lpc < max; lpc++) {
            node1 = g_list_nth_data(list1, lpc);
            node2 = g_list_nth_data(list2, lpc);
            if (node1 == NULL) {
                crm_trace("%s < %s: colocated score NULL", resource1->id, resource2->id);
                rc = 1;
                break;

            } else if (node2 == NULL) {
                crm_trace("%s > %s: colocated score NULL", resource1->id, resource2->id);
                rc = -1;
                break;
            }

            if (node1->weight < node2->weight) {
                crm_trace("%s < %s: colocated score", resource1->id, resource2->id);
                rc = 1;
                break;

            } else if (node1->weight > node2->weight) {
                crm_trace("%s > %s: colocated score", resource1->id, resource2->id);
                rc = -1;
                break;
            }
        }

        /* Order by reverse uname - same as sort_node_weight() does? */
  out:
        g_hash_table_destroy(hash1);    /* Free mem */
        g_hash_table_destroy(hash2);    /* Free mem */
        g_list_free(list1);
        g_list_free(list2);

        if (rc != 0) {
            return rc;
        }
    }

    rc = strcmp(resource1->id, resource2->id);
    crm_trace("%s %c %s: default", resource1->id, rc < 0 ? '<' : '>', resource2->id);
    return rc;
}
void import_multichannel_exr( const boost::filesystem::path& p, bool relative, bool sequence)
{
    bool tiled;

    if(!Imf::isOpenExrFile( filesystem::file_cstring( p), tiled))
    {
        app().error( "Can't open EXR file");
        return;
    }

    Imf::InputFile ifile( filesystem::file_cstring( p));
    const Imf::ChannelList& ch_list( ifile.header().channels());

    std::set<std::string> channel_set;
    for( Imf::ChannelList::ConstIterator it( ch_list.begin()); it != ch_list.end(); ++it)
        channel_set.insert( std::string( it.name()));

    if( channel_set.empty())
    {
        app().error( "EXR file has no channels");
        return;
    }

    app().document().composition().deselect_all();
    std::auto_ptr<undo::add_nodes_command_t> command( new undo::add_nodes_command_t());

    image::input_node_t *node = new image::input_node_t( p, sequence, app().document().composition().composition_dir());
    node->set_composition( &app().document().composition());
    node->create_params();
    node->select( true);
    app().ui()->main_window()->composition_view().place_node( node);

    const int node_spacing = 120;

    Imath::V2f loc( node->location());
    loc.x += node_spacing;

    std::set<std::string> layer_set;
    ch_list.layers( layer_set);

    for( std::set<std::string>::iterator sit( layer_set.begin()); sit != layer_set.end(); ++sit)
    {
        Imf::ChannelList::ConstIterator it, last;
        ch_list.channelsInLayer( *sit, it, last);

        std::auto_ptr<node_t> node_copy( new_clone( *node));
        node->set_location( loc);
        loc.x += node_spacing;
        import_layer( node_copy.get(), it, last, channel_set);
        command->add_node( node_copy);
    }

    std::vector<std::string> channels;

    // handle color layer
    if( channel_set.count( "R") || channel_set.count( "B") || channel_set.count( "B"))
    {
        channels.push_back( "A");
        channels.push_back( "B");
        channels.push_back( "G");
        channels.push_back( "R");

        std::auto_ptr<node_t> node_copy( new_clone( *node));
        node->set_location( loc);
        loc.x += node_spacing;
        import_layer( node_copy.get(), channels, channel_set);
        command->add_node( node_copy);
    }

    if( channel_set.count( "Y") || channel_set.count( "RY") || channel_set.count( "BY"))
    {
        channels.push_back( "A");
        channels.push_back( "BY");
        channels.push_back( "RY");
        channels.push_back( "Y");

        std::auto_ptr<node_t> node_copy( new_clone( *node));
        node->set_location( loc);
        loc.x += node_spacing;
        import_layer( node_copy.get(), channels, channel_set);
        command->add_node( node_copy);
    }

    if( !channel_set.empty())
    {
        for( std::set<std::string>::iterator cit( channel_set.begin()); cit != channel_set.end(); ++cit)
        {
            channels.push_back( *cit);

            if( channels.size() == 4)
            {
                std::auto_ptr<node_t> node_copy( new_clone( *node));
                node->set_location( loc);
                loc.x += node_spacing;
                import_layer( node_copy.get(), channels, channel_set);
                command->add_node( node_copy);
            }
        }

        if( !channels.empty())
        {
            std::auto_ptr<node_t> node_copy( new_clone( *node));
            node->set_location( loc);
            loc.x += node_spacing;
            import_layer( node_copy.get(), channels, channel_set);
            command->add_node( node_copy);
        }
    }

    command->redo();
    app().document().undo_stack().push_back( command);
    app().document().composition().selection_changed();
    app().ui()->update();
    delete node;
}