Btrfs: Fixup the code to merge during path walks
Add a bulk insert/remove test to random-test Add the quick-test code back as another regression test Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
bb8039515d
commit
79f95c82dc
|
@ -14,7 +14,7 @@ check=sparse $(CHECKFLAGS)
|
||||||
$(check) $<
|
$(check) $<
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
all: tester debug-tree
|
all: tester debug-tree quick-test
|
||||||
|
|
||||||
debug-tree: $(objects) debug-tree.o
|
debug-tree: $(objects) debug-tree.o
|
||||||
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o
|
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o
|
||||||
|
@ -22,6 +22,9 @@ debug-tree: $(objects) debug-tree.o
|
||||||
tester: $(objects) random-test.o
|
tester: $(objects) random-test.o
|
||||||
gcc $(CFLAGS) -o tester $(objects) random-test.o
|
gcc $(CFLAGS) -o tester $(objects) random-test.o
|
||||||
|
|
||||||
|
quick-test: $(objects) quick-test.o
|
||||||
|
gcc $(CFLAGS) -o quick-test $(objects) quick-test.o
|
||||||
|
|
||||||
$(objects) : $(headers)
|
$(objects) : $(headers)
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
|
|
135
fs/btrfs/ctree.c
135
fs/btrfs/ctree.c
|
@ -12,6 +12,9 @@ static int split_leaf(struct ctree_root *root, struct ctree_path *path,
|
||||||
int data_size);
|
int data_size);
|
||||||
static int push_node_left(struct ctree_root *root, struct tree_buffer *dst,
|
static int push_node_left(struct ctree_root *root, struct tree_buffer *dst,
|
||||||
struct tree_buffer *src);
|
struct tree_buffer *src);
|
||||||
|
static int balance_node_right(struct ctree_root *root,
|
||||||
|
struct tree_buffer *dst_buf,
|
||||||
|
struct tree_buffer *src_buf);
|
||||||
static int del_ptr(struct ctree_root *root, struct ctree_path *path, int level,
|
static int del_ptr(struct ctree_root *root, struct ctree_path *path, int level,
|
||||||
int slot);
|
int slot);
|
||||||
|
|
||||||
|
@ -217,15 +220,16 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int wret;
|
int wret;
|
||||||
int pslot;
|
int pslot;
|
||||||
int used = 0;
|
|
||||||
int count;
|
|
||||||
int orig_slot = path->slots[level];
|
int orig_slot = path->slots[level];
|
||||||
|
u64 orig_ptr;
|
||||||
|
|
||||||
if (level == 0)
|
if (level == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mid_buf = path->nodes[level];
|
mid_buf = path->nodes[level];
|
||||||
mid = &mid_buf->node;
|
mid = &mid_buf->node;
|
||||||
|
orig_ptr = mid->blockptrs[orig_slot];
|
||||||
|
|
||||||
if (level < MAX_LEVEL - 1)
|
if (level < MAX_LEVEL - 1)
|
||||||
parent_buf = path->nodes[level + 1];
|
parent_buf = path->nodes[level + 1];
|
||||||
pslot = path->slots[level + 1];
|
pslot = path->slots[level + 1];
|
||||||
|
@ -253,24 +257,26 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
|
||||||
if (mid->header.nritems > NODEPTRS_PER_BLOCK / 4)
|
if (mid->header.nritems > NODEPTRS_PER_BLOCK / 4)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// print_tree(root, root->node);
|
|
||||||
left_buf = read_node_slot(root, parent_buf, pslot - 1);
|
left_buf = read_node_slot(root, parent_buf, pslot - 1);
|
||||||
right_buf = read_node_slot(root, parent_buf, pslot + 1);
|
right_buf = read_node_slot(root, parent_buf, pslot + 1);
|
||||||
if (right_buf) {
|
|
||||||
right = &right_buf->node;
|
/* first, try to make some room in the middle buffer */
|
||||||
used = right->header.nritems;
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
if (left_buf) {
|
if (left_buf) {
|
||||||
left = &left_buf->node;
|
left = &left_buf->node;
|
||||||
used += left->header.nritems;
|
|
||||||
orig_slot += left->header.nritems;
|
orig_slot += left->header.nritems;
|
||||||
count++;
|
wret = push_node_left(root, left_buf, mid_buf);
|
||||||
|
if (wret < 0)
|
||||||
|
ret = wret;
|
||||||
}
|
}
|
||||||
if (left_buf)
|
|
||||||
push_node_left(root, left_buf, mid_buf);
|
/*
|
||||||
|
* then try to empty the right most buffer into the middle
|
||||||
|
*/
|
||||||
if (right_buf) {
|
if (right_buf) {
|
||||||
push_node_left(root, mid_buf, right_buf);
|
right = &right_buf->node;
|
||||||
|
wret = push_node_left(root, mid_buf, right_buf);
|
||||||
|
if (wret < 0)
|
||||||
|
ret = wret;
|
||||||
if (right->header.nritems == 0) {
|
if (right->header.nritems == 0) {
|
||||||
u64 blocknr = right_buf->blocknr;
|
u64 blocknr = right_buf->blocknr;
|
||||||
tree_block_release(root, right_buf);
|
tree_block_release(root, right_buf);
|
||||||
|
@ -285,9 +291,29 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
|
||||||
} else {
|
} else {
|
||||||
memcpy(parent->keys + pslot + 1, right->keys,
|
memcpy(parent->keys + pslot + 1, right->keys,
|
||||||
sizeof(struct key));
|
sizeof(struct key));
|
||||||
|
wret = write_tree_block(root, parent_buf);
|
||||||
|
if (wret)
|
||||||
|
ret = wret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mid->header.nritems == 1) {
|
||||||
|
/*
|
||||||
|
* we're not allowed to leave a node with one item in the
|
||||||
|
* tree during a delete. A deletion from lower in the tree
|
||||||
|
* could try to delete the only pointer in this node.
|
||||||
|
* So, pull some keys from the left.
|
||||||
|
* There has to be a left pointer at this point because
|
||||||
|
* otherwise we would have pulled some pointers from the
|
||||||
|
* right
|
||||||
|
*/
|
||||||
|
BUG_ON(!left_buf);
|
||||||
|
wret = balance_node_right(root, mid_buf, left_buf);
|
||||||
|
if (wret < 0)
|
||||||
|
ret = wret;
|
||||||
|
BUG_ON(wret == 1);
|
||||||
|
}
|
||||||
if (mid->header.nritems == 0) {
|
if (mid->header.nritems == 0) {
|
||||||
|
/* we've managed to empty the middle node, drop it */
|
||||||
u64 blocknr = mid_buf->blocknr;
|
u64 blocknr = mid_buf->blocknr;
|
||||||
tree_block_release(root, mid_buf);
|
tree_block_release(root, mid_buf);
|
||||||
mid_buf = NULL;
|
mid_buf = NULL;
|
||||||
|
@ -298,11 +324,17 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
|
||||||
wret = free_extent(root, blocknr, 1);
|
wret = free_extent(root, blocknr, 1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else
|
} else {
|
||||||
|
/* update the parent key to reflect our changes */
|
||||||
memcpy(parent->keys + pslot, mid->keys, sizeof(struct key));
|
memcpy(parent->keys + pslot, mid->keys, sizeof(struct key));
|
||||||
|
wret = write_tree_block(root, parent_buf);
|
||||||
|
if (wret)
|
||||||
|
ret = wret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the path */
|
||||||
if (left_buf) {
|
if (left_buf) {
|
||||||
if (left->header.nritems >= orig_slot) {
|
if (left->header.nritems > orig_slot) {
|
||||||
left_buf->count++; // released below
|
left_buf->count++; // released below
|
||||||
path->nodes[level] = left_buf;
|
path->nodes[level] = left_buf;
|
||||||
path->slots[level + 1] -= 1;
|
path->slots[level + 1] -= 1;
|
||||||
|
@ -314,12 +346,15 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
|
||||||
path->slots[level] = orig_slot;
|
path->slots[level] = orig_slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* double check we haven't messed things up */
|
||||||
|
check_block(path, level);
|
||||||
|
if (orig_ptr != path->nodes[level]->node.blockptrs[path->slots[level]])
|
||||||
|
BUG();
|
||||||
|
|
||||||
if (right_buf)
|
if (right_buf)
|
||||||
tree_block_release(root, right_buf);
|
tree_block_release(root, right_buf);
|
||||||
if (left_buf)
|
if (left_buf)
|
||||||
tree_block_release(root, left_buf);
|
tree_block_release(root, left_buf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +413,7 @@ int search_slot(struct ctree_root *root, struct key *key,
|
||||||
goto again;
|
goto again;
|
||||||
c = &b->node;
|
c = &b->node;
|
||||||
slot = p->slots[level];
|
slot = p->slots[level];
|
||||||
|
BUG_ON(c->header.nritems == 1);
|
||||||
}
|
}
|
||||||
b = read_tree_block(root, c->blockptrs[slot]);
|
b = read_tree_block(root, c->blockptrs[slot]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -433,13 +469,7 @@ static int fixup_low_keys(struct ctree_root *root,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* try to push data from one node into the next node left in the
|
* try to push data from one node into the next node left in the
|
||||||
* tree. The src node is found at specified level in the path.
|
* tree.
|
||||||
* If some bytes were pushed, return 0, otherwise return 1.
|
|
||||||
*
|
|
||||||
* Lower nodes/leaves in the path are not touched, higher nodes may
|
|
||||||
* be modified to reflect the push.
|
|
||||||
*
|
|
||||||
* The path is altered to reflect the push.
|
|
||||||
*
|
*
|
||||||
* returns 0 if some ptrs were pushed left, < 0 if there was some horrible
|
* returns 0 if some ptrs were pushed left, < 0 if there was some horrible
|
||||||
* error, and > 0 if there was no room in the left hand block.
|
* error, and > 0 if there was no room in the left hand block.
|
||||||
|
@ -464,6 +494,7 @@ static int push_node_left(struct ctree_root *root, struct tree_buffer *dst_buf,
|
||||||
|
|
||||||
if (src_nritems < push_items)
|
if (src_nritems < push_items)
|
||||||
push_items = src_nritems;
|
push_items = src_nritems;
|
||||||
|
|
||||||
memcpy(dst->keys + dst_nritems, src->keys,
|
memcpy(dst->keys + dst_nritems, src->keys,
|
||||||
push_items * sizeof(struct key));
|
push_items * sizeof(struct key));
|
||||||
memcpy(dst->blockptrs + dst_nritems, src->blockptrs,
|
memcpy(dst->blockptrs + dst_nritems, src->blockptrs,
|
||||||
|
@ -487,6 +518,64 @@ static int push_node_left(struct ctree_root *root, struct tree_buffer *dst_buf,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try to push data from one node into the next node right in the
|
||||||
|
* tree.
|
||||||
|
*
|
||||||
|
* returns 0 if some ptrs were pushed, < 0 if there was some horrible
|
||||||
|
* error, and > 0 if there was no room in the right hand block.
|
||||||
|
*
|
||||||
|
* this will only push up to 1/2 the contents of the left node over
|
||||||
|
*/
|
||||||
|
static int balance_node_right(struct ctree_root *root,
|
||||||
|
struct tree_buffer *dst_buf,
|
||||||
|
struct tree_buffer *src_buf)
|
||||||
|
{
|
||||||
|
struct node *src = &src_buf->node;
|
||||||
|
struct node *dst = &dst_buf->node;
|
||||||
|
int push_items = 0;
|
||||||
|
int max_push;
|
||||||
|
int src_nritems;
|
||||||
|
int dst_nritems;
|
||||||
|
int ret = 0;
|
||||||
|
int wret;
|
||||||
|
|
||||||
|
src_nritems = src->header.nritems;
|
||||||
|
dst_nritems = dst->header.nritems;
|
||||||
|
push_items = NODEPTRS_PER_BLOCK - dst_nritems;
|
||||||
|
if (push_items <= 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_push = src_nritems / 2 + 1;
|
||||||
|
/* don't try to empty the node */
|
||||||
|
if (max_push > src_nritems)
|
||||||
|
return 1;
|
||||||
|
if (max_push < push_items)
|
||||||
|
push_items = max_push;
|
||||||
|
|
||||||
|
memmove(dst->keys + push_items, dst->keys,
|
||||||
|
dst_nritems * sizeof(struct key));
|
||||||
|
memmove(dst->blockptrs + push_items, dst->blockptrs,
|
||||||
|
dst_nritems * sizeof(u64));
|
||||||
|
memcpy(dst->keys, src->keys + src_nritems - push_items,
|
||||||
|
push_items * sizeof(struct key));
|
||||||
|
memcpy(dst->blockptrs, src->blockptrs + src_nritems - push_items,
|
||||||
|
push_items * sizeof(u64));
|
||||||
|
|
||||||
|
src->header.nritems -= push_items;
|
||||||
|
dst->header.nritems += push_items;
|
||||||
|
|
||||||
|
wret = write_tree_block(root, src_buf);
|
||||||
|
if (wret < 0)
|
||||||
|
ret = wret;
|
||||||
|
|
||||||
|
wret = write_tree_block(root, dst_buf);
|
||||||
|
if (wret < 0)
|
||||||
|
ret = wret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* helper function to insert a new root level in the tree.
|
* helper function to insert a new root level in the tree.
|
||||||
* A new node is allocated, and a single item is inserted to
|
* A new node is allocated, and a single item is inserted to
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "kerncompat.h"
|
||||||
|
#include "radix-tree.h"
|
||||||
|
#include "ctree.h"
|
||||||
|
#include "disk-io.h"
|
||||||
|
#include "print-tree.h"
|
||||||
|
|
||||||
|
/* for testing only */
|
||||||
|
int next_key(int i, int max_key) {
|
||||||
|
return rand() % max_key;
|
||||||
|
//return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ac, char **av) {
|
||||||
|
struct key ins;
|
||||||
|
struct key last = { (u64)-1, 0, 0};
|
||||||
|
char *buf;
|
||||||
|
int i;
|
||||||
|
int num;
|
||||||
|
int ret;
|
||||||
|
int run_size = 100000;
|
||||||
|
int max_key = 100000000;
|
||||||
|
int tree_size = 0;
|
||||||
|
struct ctree_path path;
|
||||||
|
struct ctree_super_block super;
|
||||||
|
struct ctree_root *root;
|
||||||
|
|
||||||
|
radix_tree_init();
|
||||||
|
|
||||||
|
root = open_ctree("dbfile", &super);
|
||||||
|
srand(55);
|
||||||
|
for (i = 0; i < run_size; i++) {
|
||||||
|
buf = malloc(64);
|
||||||
|
num = next_key(i, max_key);
|
||||||
|
// num = i;
|
||||||
|
sprintf(buf, "string-%d", num);
|
||||||
|
if (i % 10000 == 0)
|
||||||
|
fprintf(stderr, "insert %d:%d\n", num, i);
|
||||||
|
ins.objectid = num;
|
||||||
|
ins.offset = 0;
|
||||||
|
ins.flags = 0;
|
||||||
|
ret = insert_item(root, &ins, buf, strlen(buf));
|
||||||
|
if (!ret)
|
||||||
|
tree_size++;
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
write_ctree_super(root, &super);
|
||||||
|
close_ctree(root);
|
||||||
|
|
||||||
|
root = open_ctree("dbfile", &super);
|
||||||
|
printf("starting search\n");
|
||||||
|
srand(55);
|
||||||
|
for (i = 0; i < run_size; i++) {
|
||||||
|
num = next_key(i, max_key);
|
||||||
|
ins.objectid = num;
|
||||||
|
init_path(&path);
|
||||||
|
if (i % 10000 == 0)
|
||||||
|
fprintf(stderr, "search %d:%d\n", num, i);
|
||||||
|
ret = search_slot(root, &ins, &path, 0);
|
||||||
|
if (ret) {
|
||||||
|
print_tree(root, root->node);
|
||||||
|
printf("unable to find %d\n", num);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
release_path(root, &path);
|
||||||
|
}
|
||||||
|
write_ctree_super(root, &super);
|
||||||
|
close_ctree(root);
|
||||||
|
root = open_ctree("dbfile", &super);
|
||||||
|
printf("node %p level %d total ptrs %d free spc %lu\n", root->node,
|
||||||
|
node_level(root->node->node.header.flags),
|
||||||
|
root->node->node.header.nritems,
|
||||||
|
NODEPTRS_PER_BLOCK - root->node->node.header.nritems);
|
||||||
|
printf("all searches good, deleting some items\n");
|
||||||
|
i = 0;
|
||||||
|
srand(55);
|
||||||
|
for (i = 0 ; i < run_size/4; i++) {
|
||||||
|
num = next_key(i, max_key);
|
||||||
|
ins.objectid = num;
|
||||||
|
init_path(&path);
|
||||||
|
ret = search_slot(root, &ins, &path, -1);
|
||||||
|
if (!ret) {
|
||||||
|
if (i % 10000 == 0)
|
||||||
|
fprintf(stderr, "del %d:%d\n", num, i);
|
||||||
|
ret = del_item(root, &path);
|
||||||
|
if (ret != 0)
|
||||||
|
BUG();
|
||||||
|
tree_size--;
|
||||||
|
}
|
||||||
|
release_path(root, &path);
|
||||||
|
}
|
||||||
|
write_ctree_super(root, &super);
|
||||||
|
close_ctree(root);
|
||||||
|
root = open_ctree("dbfile", &super);
|
||||||
|
srand(128);
|
||||||
|
for (i = 0; i < run_size; i++) {
|
||||||
|
buf = malloc(64);
|
||||||
|
num = next_key(i, max_key);
|
||||||
|
sprintf(buf, "string-%d", num);
|
||||||
|
ins.objectid = num;
|
||||||
|
if (i % 10000 == 0)
|
||||||
|
fprintf(stderr, "insert %d:%d\n", num, i);
|
||||||
|
ret = insert_item(root, &ins, buf, strlen(buf));
|
||||||
|
if (!ret)
|
||||||
|
tree_size++;
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
write_ctree_super(root, &super);
|
||||||
|
close_ctree(root);
|
||||||
|
root = open_ctree("dbfile", &super);
|
||||||
|
srand(128);
|
||||||
|
printf("starting search2\n");
|
||||||
|
for (i = 0; i < run_size; i++) {
|
||||||
|
num = next_key(i, max_key);
|
||||||
|
ins.objectid = num;
|
||||||
|
init_path(&path);
|
||||||
|
if (i % 10000 == 0)
|
||||||
|
fprintf(stderr, "search %d:%d\n", num, i);
|
||||||
|
ret = search_slot(root, &ins, &path, 0);
|
||||||
|
if (ret) {
|
||||||
|
print_tree(root, root->node);
|
||||||
|
printf("unable to find %d\n", num);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
release_path(root, &path);
|
||||||
|
}
|
||||||
|
printf("starting big long delete run\n");
|
||||||
|
while(root->node && root->node->node.header.nritems > 0) {
|
||||||
|
struct leaf *leaf;
|
||||||
|
int slot;
|
||||||
|
ins.objectid = (u64)-1;
|
||||||
|
init_path(&path);
|
||||||
|
ret = search_slot(root, &ins, &path, -1);
|
||||||
|
if (ret == 0)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
leaf = &path.nodes[0]->leaf;
|
||||||
|
slot = path.slots[0];
|
||||||
|
if (slot != leaf->header.nritems)
|
||||||
|
BUG();
|
||||||
|
while(path.slots[0] > 0) {
|
||||||
|
path.slots[0] -= 1;
|
||||||
|
slot = path.slots[0];
|
||||||
|
leaf = &path.nodes[0]->leaf;
|
||||||
|
|
||||||
|
memcpy(&last, &leaf->items[slot].key, sizeof(last));
|
||||||
|
if (tree_size % 10000 == 0)
|
||||||
|
printf("big del %d:%d\n", tree_size, i);
|
||||||
|
ret = del_item(root, &path);
|
||||||
|
if (ret != 0) {
|
||||||
|
printf("del_item returned %d\n", ret);
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
tree_size--;
|
||||||
|
}
|
||||||
|
release_path(root, &path);
|
||||||
|
}
|
||||||
|
printf("tree size is now %d\n", tree_size);
|
||||||
|
printf("map tree\n");
|
||||||
|
print_tree(root->extent_root, root->extent_root->node);
|
||||||
|
write_ctree_super(root, &super);
|
||||||
|
close_ctree(root);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -142,8 +142,98 @@ static int lookup_enoent(struct ctree_root *root, struct radix_tree_root *radix)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int empty_tree(struct ctree_root *root, struct radix_tree_root *radix,
|
||||||
|
int nr)
|
||||||
|
{
|
||||||
|
struct ctree_path path;
|
||||||
|
struct key key;
|
||||||
|
unsigned long found = 0;
|
||||||
|
int ret;
|
||||||
|
int slot;
|
||||||
|
int *ptr;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
key.offset = 0;
|
||||||
|
key.flags = 0;
|
||||||
|
key.objectid = (unsigned long)-1;
|
||||||
|
while(nr-- >= 0) {
|
||||||
|
init_path(&path);
|
||||||
|
ret = search_slot(root, &key, &path, -1);
|
||||||
|
if (ret < 0) {
|
||||||
|
release_path(root, &path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
if (path.slots[0] == 0) {
|
||||||
|
release_path(root, &path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path.slots[0] -= 1;
|
||||||
|
}
|
||||||
|
slot = path.slots[0];
|
||||||
|
found = path.nodes[0]->leaf.items[slot].key.objectid;
|
||||||
|
ret = del_item(root, &path);
|
||||||
|
count++;
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"failed to remove %lu from tree\n",
|
||||||
|
found);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
release_path(root, &path);
|
||||||
|
ptr = radix_tree_delete(radix, found);
|
||||||
|
if (!ptr)
|
||||||
|
goto error;
|
||||||
|
if (!keep_running)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
fprintf(stderr, "failed to delete from the radix %lu\n", found);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fill_tree(struct ctree_root *root, struct radix_tree_root *radix,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int err;
|
||||||
|
int ret = 0;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
ret = ins_one(root, radix);
|
||||||
|
if (ret) {
|
||||||
|
printf("fill failed\n");
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!keep_running)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bulk_op(struct ctree_root *root, struct radix_tree_root *radix)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int nr = rand() % 20000;
|
||||||
|
static int run_nr = 0;
|
||||||
|
|
||||||
|
/* do the bulk op much less frequently */
|
||||||
|
if (run_nr++ % 100)
|
||||||
|
return 0;
|
||||||
|
ret = empty_tree(root, radix, nr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = fill_tree(root, radix, nr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int (*ops[])(struct ctree_root *root, struct radix_tree_root *radix) =
|
int (*ops[])(struct ctree_root *root, struct radix_tree_root *radix) =
|
||||||
{ ins_one, insert_dup, del_one, lookup_item, lookup_enoent };
|
{ ins_one, insert_dup, del_one, lookup_item, lookup_enoent, bulk_op };
|
||||||
|
|
||||||
static int fill_radix(struct ctree_root *root, struct radix_tree_root *radix)
|
static int fill_radix(struct ctree_root *root, struct radix_tree_root *radix)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +282,6 @@ static int fill_radix(struct ctree_root *root, struct radix_tree_root *radix)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sigstopper(int ignored)
|
void sigstopper(int ignored)
|
||||||
{
|
{
|
||||||
keep_running = 0;
|
keep_running = 0;
|
||||||
|
@ -241,23 +330,13 @@ int main(int ac, char **av)
|
||||||
print_usage();
|
print_usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < init_fill_count; i++) {
|
printf("initial fill\n");
|
||||||
ret = ins_one(root, &radix);
|
ret = fill_tree(root, &radix, init_fill_count);
|
||||||
|
printf("starting run\n");
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("initial fill failed\n");
|
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (i % 10000 == 0) {
|
|
||||||
printf("initial fill %d level %d count %d\n", i,
|
|
||||||
node_level(root->node->node.header.flags),
|
|
||||||
root->node->node.header.nritems);
|
|
||||||
}
|
|
||||||
if (keep_running == 0) {
|
|
||||||
err = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (initial_only == 1) {
|
if (initial_only == 1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -287,6 +366,8 @@ int main(int ac, char **av)
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (ops[op] == bulk_op)
|
||||||
|
break;
|
||||||
if (keep_running == 0) {
|
if (keep_running == 0) {
|
||||||
err = 0;
|
err = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Loading…
Reference in New Issue