Example #1
0
static void
test_ght_hash_leaf_parts(void)
{
    /*
    GhtErr
    ght_hash_leaf_parts(const GhtHash *a, const GhtHash *b, int maxlen,
                        GhtHashMatch *matchtype, GhtHash **a_leaf, GhtHash **b_leaf)
    */
    GhtHash *a, *b;
    GhtHash *a_leaf, *b_leaf;
    GhtHashMatch matchtype;
    GhtErr e;
    int maxlen = 5;

    a = "abcdefgh";
    b = "abcdefgh";
    maxlen = 8;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_OK);
    CU_ASSERT_EQUAL(matchtype, GHT_SAME);

    maxlen = 5;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_OK);
    CU_ASSERT_EQUAL(matchtype, GHT_SPLIT);
    CU_ASSERT_STRING_EQUAL(a_leaf, "fgh");
    CU_ASSERT_STRING_EQUAL(b_leaf, "fgh");

    a = "abcde";
    b = "abcdefgh";
    maxlen = 8;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_OK);
    CU_ASSERT_EQUAL(matchtype, GHT_CHILD);
    CU_ASSERT_STRING_EQUAL(b_leaf, "fgh");

    a = "abcde";
    b = "1abcdefgh";
    maxlen = 8;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_ERROR);
    CU_ASSERT_EQUAL(matchtype, GHT_NONE);

    a = "";
    b = "1abcdefgh";
    maxlen = 8;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_OK);
    CU_ASSERT_EQUAL(matchtype, GHT_GLOBAL);

    a = "abcdafda";
    b = "1abcdh";
    maxlen = 8;
    e = ght_hash_leaf_parts(a, b, maxlen, &matchtype, &a_leaf, &b_leaf);
    CU_ASSERT_EQUAL(e, GHT_ERROR);
    CU_ASSERT_EQUAL(matchtype, GHT_NONE);

}
Example #2
0
/**
 * Recursive function, walk down from parent node, looking for
 * appropriate insertion point for node_to_insert. If duplicates,
 * and duplicate leaf, insert as hash-less "attribute only" node.
 * ["abcdefg", "abcdeff", "abcdddd", "abbbeee"] becomes
 * "ab"->["c"->["d"->["ddd","ef"->["g","f"]]],"b"]
 */
GhtErr
ght_node_insert_node(GhtNode *node, GhtNode *node_to_insert, GhtDuplicates duplicates)
{
	GhtHash *node_leaf, *node_to_insert_leaf;
	GhtErr err;
	GhtHashMatch matchtype;

	/* NULL hash implies this node is a faux node for duplicate points */
	if ( ! node->hash )
		return GHT_INCOMPLETE;

	/* matchtype in (GHT_NONE, GHT_GLOBAL, GHT_SAME, GHT_CHILD, GHT_SPLIT) */
	/* NONE and GLOBAL come back with GHT_ERROR, so we don't handle them yet */
	GHT_TRY(ght_hash_leaf_parts(node->hash, node_to_insert->hash, GHT_MAX_HASH_LENGTH,
			&matchtype, &node_leaf, &node_to_insert_leaf));

	/* Insert node is child of node, either explicitly, or implicitly for */
	/* the "" hash which serves as a master parent */
	/* "abcdef" is a GHT_CHILD or "abc", and gets added as "def" */
	if ( matchtype == GHT_CHILD || matchtype == GHT_GLOBAL )
	{
		int i;
		ght_node_set_hash(node_to_insert, ght_strdup(node_to_insert_leaf));
		for ( i = 0; i < ght_node_num_children(node); i++ )
		{
			err = ght_node_insert_node(node->children->nodes[i], node_to_insert, duplicates);
			/* Node added to one of the children */
			if ( err == GHT_OK ) return GHT_OK;
		}
		/* Node didn't fit any of the children, so add it at this level */
		return ght_node_add_child(node, node_to_insert);
	}

	if ( matchtype == GHT_SAME )
	{
		/* New node is duplicate of this node. We insert an */
		/* empty node (no hash) underneath, to hang attributes off of */
		/* and use this node as the parent */
		if ( duplicates )
		{
			/* If this is the first duplicate, add a copy of the parent */
			/* To serve as a proxy leaf for this value */
			if ( ( ! node->children ) || ( node->children->num_nodes == 0 ) )
			{
				GhtNode *parent_leaf;
				GHT_TRY(ght_node_new(&parent_leaf));
				GHT_TRY(ght_node_transfer_attributes(node, parent_leaf));
				GHT_TRY(ght_node_add_child(node, parent_leaf));
			}

			/* Add the new node under the parent, stripping the hash */
			ght_free(node_to_insert->hash);
			node_to_insert->hash = NULL;
			GHT_TRY(ght_node_add_child(node, node_to_insert));

			return GHT_OK;
		}
		else
		{
			/* For now, we just skip duplicates. */
			/* In future, average / median the duplicates onto parent here? */
			return GHT_OK;
		}
	}

	/* "abcdef" and "abcghi" need to GHT_SPLIT, into "abc"->["def", "ghi"] */
	if ( matchtype == GHT_SPLIT )
	{
		/* We need a new node to hold that part of the parent that is not shared */
		GhtNode *another_node_to_insert;
		GHT_TRY(ght_node_new_from_hash(node_leaf, &another_node_to_insert));
		/* Move attributes to the new child */
		GHT_TRY(ght_node_transfer_attributes(node, another_node_to_insert));

		/* Any children of the parent need to move down the tree with the unique part of the hash */
		if ( node->children )
		{
			another_node_to_insert->children = node->children;
			node->children = NULL;
		}
		/* Null-terminate parent hash at end of shared part */
		*node_leaf = '\0';
		/* Pull the non-shared part of insert node hash to the front */
		memmove(node_to_insert->hash, node_to_insert_leaf, strlen(node_to_insert_leaf)+1);
		/* Add the unique portion of the parent to the parent */
		GHT_TRY(ght_node_add_child(node, another_node_to_insert));
		/* Add the unique portion of the insert node to the parent */
		GHT_TRY(ght_node_add_child(node, node_to_insert));
		/* Done! */
		return GHT_OK;
	}

	/* Don't get here */
	return GHT_ERROR;

}