* @param ttl: Element is valid up to this time. Absolute, seconds
* @return new addrnode or NULL on failure
*/
-static struct addrnode*
-node_create(void* elem, addrlen_t scope, time_t ttl)
+static struct addrnode *
+node_create(struct addrtree *tree, void* elem, addrlen_t scope,
+ time_t ttl)
{
struct addrnode* node = (struct addrnode*)malloc( sizeof (*node) );
if (!node)
return NULL;
node->elem = elem;
+ if (elem) tree->elem_count++;
node->scope = scope;
node->ttl = ttl;
node->edge[0] = NULL;
tree = (struct addrtree*)malloc( sizeof (*tree) );
if(!tree)
return NULL;
- tree->root = node_create(NULL, 0, 0);
+ tree->root = node_create(tree, NULL, 0, 0);
if (!tree->root) {
free(tree);
return NULL;
tree->delfunc = delfunc;
tree->sizefunc = sizefunc;
tree->env = env;
+ tree->elem_count = 0;
return tree;
}
* @param node: Node to be cleaned
*/
static void
-clean_node(const struct addrtree* tree, struct addrnode* node)
+clean_node(struct addrtree* tree, struct addrnode* node)
{
if (!node->elem) return;
tree->delfunc(tree->env, node->elem);
node->elem = NULL;
+ tree->elem_count--;
}
/**
* parentnode is NULL
*/
static void
-purge_node(const struct addrtree* tree, struct addrnode* node,
+purge_node(struct addrtree* tree, struct addrnode* node,
struct addrnode* parentnode, struct addredge* parentedge)
{
struct addredge *child_edge = NULL;
if (depth == sourcemask) {
/* update this node's scope and data */
clean_node(tree, node);
+ tree->elem_count++;
node->elem = elem;
node->scope = scope;
return;
}
/* Case 2: New leafnode */
if (!edge) {
- newnode = node_create(elem, scope, ttl);
+ newnode = node_create(tree, elem, scope, ttl);
node->edge[index] = edge_create(newnode, addr, sourcemask);
if (!node->edge[index])
free(newnode);
continue;
}
/* Case 4: split. */
- if (!(newnode = node_create(NULL, 0, 0)))
+ if (!(newnode = node_create(tree, NULL, 0, 0)))
return;
if (!(newedge = edge_create(newnode, addr, common))) {
+ clean_node(tree, newnode);
free(newnode);
return;
}
} else {
/* Data is stored in other leafnode */
node = newnode;
- newnode = node_create(elem, scope, ttl);
+ newnode = node_create(tree, elem, scope, ttl);
node->edge[index^1] = edge_create(newnode, addr, sourcemask);
}
return;
static void consistency_test(void)
{
int i, l, r;
+ unsigned int count;
addrkey_t *k;
struct addrtree* t;
struct module_env env;
srand(9195); /* just some value for reproducibility */
t = addrtree_create(100, &elemfree, NULL, &env);
+ count = t->elem_count;
+ unit_assert(count == 0);
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow);
+ /* This should always hold because no items ever expire. They
+ * could be overwritten, though. */
+ unit_assert( count <= t->elem_count );
+ count = t->elem_count;
free(k);
unit_assert( !addrtree_inconsistent(t) );
}
addrtree_delete(t);
unit_show_func("edns-subnet/addrtree.h", "Tree consistency with purge");
t = addrtree_create(8, &elemfree, NULL, &env);
+ unit_assert(t->elem_count == 0);
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));