mirror of
https://github.com/fluencelabs/redis
synced 2025-06-12 00:31:21 +00:00
Jemalloc updated to 3.6.0.
Not a single bug in about 3 months, and our previous version was too old (3.2.0).
This commit is contained in:
333
deps/jemalloc/test/unit/rb.c
vendored
Normal file
333
deps/jemalloc/test/unit/rb.c
vendored
Normal file
@ -0,0 +1,333 @@
|
||||
#include "test/jemalloc_test.h"
|
||||
|
||||
#define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \
|
||||
a_type *rbp_bh_t; \
|
||||
for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; \
|
||||
rbp_bh_t != &(a_rbt)->rbt_nil; \
|
||||
rbp_bh_t = rbtn_left_get(a_type, a_field, rbp_bh_t)) { \
|
||||
if (rbtn_red_get(a_type, a_field, rbp_bh_t) == false) { \
|
||||
(r_height)++; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct node_s node_t;
|
||||
|
||||
struct node_s {
|
||||
#define NODE_MAGIC 0x9823af7e
|
||||
uint32_t magic;
|
||||
rb_node(node_t) link;
|
||||
uint64_t key;
|
||||
};
|
||||
|
||||
static int
|
||||
node_cmp(node_t *a, node_t *b) {
|
||||
int ret;
|
||||
|
||||
assert_u32_eq(a->magic, NODE_MAGIC, "Bad magic");
|
||||
assert_u32_eq(b->magic, NODE_MAGIC, "Bad magic");
|
||||
|
||||
ret = (a->key > b->key) - (a->key < b->key);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Duplicates are not allowed in the tree, so force an
|
||||
* arbitrary ordering for non-identical items with equal keys.
|
||||
*/
|
||||
ret = (((uintptr_t)a) > ((uintptr_t)b))
|
||||
- (((uintptr_t)a) < ((uintptr_t)b));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
typedef rb_tree(node_t) tree_t;
|
||||
rb_gen(static, tree_, tree_t, node_t, link, node_cmp);
|
||||
|
||||
TEST_BEGIN(test_rb_empty)
|
||||
{
|
||||
tree_t tree;
|
||||
node_t key;
|
||||
|
||||
tree_new(&tree);
|
||||
|
||||
assert_ptr_null(tree_first(&tree), "Unexpected node");
|
||||
assert_ptr_null(tree_last(&tree), "Unexpected node");
|
||||
|
||||
key.key = 0;
|
||||
key.magic = NODE_MAGIC;
|
||||
assert_ptr_null(tree_search(&tree, &key), "Unexpected node");
|
||||
|
||||
key.key = 0;
|
||||
key.magic = NODE_MAGIC;
|
||||
assert_ptr_null(tree_nsearch(&tree, &key), "Unexpected node");
|
||||
|
||||
key.key = 0;
|
||||
key.magic = NODE_MAGIC;
|
||||
assert_ptr_null(tree_psearch(&tree, &key), "Unexpected node");
|
||||
}
|
||||
TEST_END
|
||||
|
||||
static unsigned
|
||||
tree_recurse(node_t *node, unsigned black_height, unsigned black_depth,
|
||||
node_t *nil)
|
||||
{
|
||||
unsigned ret = 0;
|
||||
node_t *left_node = rbtn_left_get(node_t, link, node);
|
||||
node_t *right_node = rbtn_right_get(node_t, link, node);
|
||||
|
||||
if (rbtn_red_get(node_t, link, node) == false)
|
||||
black_depth++;
|
||||
|
||||
/* Red nodes must be interleaved with black nodes. */
|
||||
if (rbtn_red_get(node_t, link, node)) {
|
||||
assert_false(rbtn_red_get(node_t, link, left_node),
|
||||
"Node should be black");
|
||||
assert_false(rbtn_red_get(node_t, link, right_node),
|
||||
"Node should be black");
|
||||
}
|
||||
|
||||
if (node == nil)
|
||||
return (ret);
|
||||
/* Self. */
|
||||
assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic");
|
||||
|
||||
/* Left subtree. */
|
||||
if (left_node != nil)
|
||||
ret += tree_recurse(left_node, black_height, black_depth, nil);
|
||||
else
|
||||
ret += (black_depth != black_height);
|
||||
|
||||
/* Right subtree. */
|
||||
if (right_node != nil)
|
||||
ret += tree_recurse(right_node, black_height, black_depth, nil);
|
||||
else
|
||||
ret += (black_depth != black_height);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static node_t *
|
||||
tree_iterate_cb(tree_t *tree, node_t *node, void *data)
|
||||
{
|
||||
unsigned *i = (unsigned *)data;
|
||||
node_t *search_node;
|
||||
|
||||
assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic");
|
||||
|
||||
/* Test rb_search(). */
|
||||
search_node = tree_search(tree, node);
|
||||
assert_ptr_eq(search_node, node,
|
||||
"tree_search() returned unexpected node");
|
||||
|
||||
/* Test rb_nsearch(). */
|
||||
search_node = tree_nsearch(tree, node);
|
||||
assert_ptr_eq(search_node, node,
|
||||
"tree_nsearch() returned unexpected node");
|
||||
|
||||
/* Test rb_psearch(). */
|
||||
search_node = tree_psearch(tree, node);
|
||||
assert_ptr_eq(search_node, node,
|
||||
"tree_psearch() returned unexpected node");
|
||||
|
||||
(*i)++;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
tree_iterate(tree_t *tree)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
i = 0;
|
||||
tree_iter(tree, NULL, tree_iterate_cb, (void *)&i);
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
tree_iterate_reverse(tree_t *tree)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
i = 0;
|
||||
tree_reverse_iter(tree, NULL, tree_iterate_cb, (void *)&i);
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static void
|
||||
node_remove(tree_t *tree, node_t *node, unsigned nnodes)
|
||||
{
|
||||
node_t *search_node;
|
||||
unsigned black_height, imbalances;
|
||||
|
||||
tree_remove(tree, node);
|
||||
|
||||
/* Test rb_nsearch(). */
|
||||
search_node = tree_nsearch(tree, node);
|
||||
if (search_node != NULL) {
|
||||
assert_u64_ge(search_node->key, node->key,
|
||||
"Key ordering error");
|
||||
}
|
||||
|
||||
/* Test rb_psearch(). */
|
||||
search_node = tree_psearch(tree, node);
|
||||
if (search_node != NULL) {
|
||||
assert_u64_le(search_node->key, node->key,
|
||||
"Key ordering error");
|
||||
}
|
||||
|
||||
node->magic = 0;
|
||||
|
||||
rbtn_black_height(node_t, link, tree, black_height);
|
||||
imbalances = tree_recurse(tree->rbt_root, black_height, 0,
|
||||
&(tree->rbt_nil));
|
||||
assert_u_eq(imbalances, 0, "Tree is unbalanced");
|
||||
assert_u_eq(tree_iterate(tree), nnodes-1,
|
||||
"Unexpected node iteration count");
|
||||
assert_u_eq(tree_iterate_reverse(tree), nnodes-1,
|
||||
"Unexpected node iteration count");
|
||||
}
|
||||
|
||||
static node_t *
|
||||
remove_iterate_cb(tree_t *tree, node_t *node, void *data)
|
||||
{
|
||||
unsigned *nnodes = (unsigned *)data;
|
||||
node_t *ret = tree_next(tree, node);
|
||||
|
||||
node_remove(tree, node, *nnodes);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static node_t *
|
||||
remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data)
|
||||
{
|
||||
unsigned *nnodes = (unsigned *)data;
|
||||
node_t *ret = tree_prev(tree, node);
|
||||
|
||||
node_remove(tree, node, *nnodes);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
TEST_BEGIN(test_rb_random)
|
||||
{
|
||||
#define NNODES 25
|
||||
#define NBAGS 250
|
||||
#define SEED 42
|
||||
sfmt_t *sfmt;
|
||||
uint64_t bag[NNODES];
|
||||
tree_t tree;
|
||||
node_t nodes[NNODES];
|
||||
unsigned i, j, k, black_height, imbalances;
|
||||
|
||||
sfmt = init_gen_rand(SEED);
|
||||
for (i = 0; i < NBAGS; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
/* Insert in order. */
|
||||
for (j = 0; j < NNODES; j++)
|
||||
bag[j] = j;
|
||||
break;
|
||||
case 1:
|
||||
/* Insert in reverse order. */
|
||||
for (j = 0; j < NNODES; j++)
|
||||
bag[j] = NNODES - j - 1;
|
||||
break;
|
||||
default:
|
||||
for (j = 0; j < NNODES; j++)
|
||||
bag[j] = gen_rand64_range(sfmt, NNODES);
|
||||
}
|
||||
|
||||
for (j = 1; j <= NNODES; j++) {
|
||||
/* Initialize tree and nodes. */
|
||||
tree_new(&tree);
|
||||
tree.rbt_nil.magic = 0;
|
||||
for (k = 0; k < j; k++) {
|
||||
nodes[k].magic = NODE_MAGIC;
|
||||
nodes[k].key = bag[k];
|
||||
}
|
||||
|
||||
/* Insert nodes. */
|
||||
for (k = 0; k < j; k++) {
|
||||
tree_insert(&tree, &nodes[k]);
|
||||
|
||||
rbtn_black_height(node_t, link, &tree,
|
||||
black_height);
|
||||
imbalances = tree_recurse(tree.rbt_root,
|
||||
black_height, 0, &(tree.rbt_nil));
|
||||
assert_u_eq(imbalances, 0,
|
||||
"Tree is unbalanced");
|
||||
|
||||
assert_u_eq(tree_iterate(&tree), k+1,
|
||||
"Unexpected node iteration count");
|
||||
assert_u_eq(tree_iterate_reverse(&tree), k+1,
|
||||
"Unexpected node iteration count");
|
||||
|
||||
assert_ptr_not_null(tree_first(&tree),
|
||||
"Tree should not be empty");
|
||||
assert_ptr_not_null(tree_last(&tree),
|
||||
"Tree should not be empty");
|
||||
|
||||
tree_next(&tree, &nodes[k]);
|
||||
tree_prev(&tree, &nodes[k]);
|
||||
}
|
||||
|
||||
/* Remove nodes. */
|
||||
switch (i % 4) {
|
||||
case 0:
|
||||
for (k = 0; k < j; k++)
|
||||
node_remove(&tree, &nodes[k], j - k);
|
||||
break;
|
||||
case 1:
|
||||
for (k = j; k > 0; k--)
|
||||
node_remove(&tree, &nodes[k-1], k);
|
||||
break;
|
||||
case 2: {
|
||||
node_t *start;
|
||||
unsigned nnodes = j;
|
||||
|
||||
start = NULL;
|
||||
do {
|
||||
start = tree_iter(&tree, start,
|
||||
remove_iterate_cb, (void *)&nnodes);
|
||||
nnodes--;
|
||||
} while (start != NULL);
|
||||
assert_u_eq(nnodes, 0,
|
||||
"Removal terminated early");
|
||||
break;
|
||||
} case 3: {
|
||||
node_t *start;
|
||||
unsigned nnodes = j;
|
||||
|
||||
start = NULL;
|
||||
do {
|
||||
start = tree_reverse_iter(&tree, start,
|
||||
remove_reverse_iterate_cb,
|
||||
(void *)&nnodes);
|
||||
nnodes--;
|
||||
} while (start != NULL);
|
||||
assert_u_eq(nnodes, 0,
|
||||
"Removal terminated early");
|
||||
break;
|
||||
} default:
|
||||
not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
fini_gen_rand(sfmt);
|
||||
#undef NNODES
|
||||
#undef NBAGS
|
||||
#undef SEED
|
||||
}
|
||||
TEST_END
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
|
||||
return (test(
|
||||
test_rb_empty,
|
||||
test_rb_random));
|
||||
}
|
Reference in New Issue
Block a user