Commit 95c2b107 authored by Zardosht Kasheff's avatar Zardosht Kasheff Committed by Yoni Fogel

[t:4388], add test for splits

git-svn-id: file:///svn/toku/tokudb@38806 c7de825b-a66e-492c-adef-691d508d4ae1
parent 86e1855c
......@@ -247,6 +247,7 @@ doit (BOOL after_child_pin) {
int
test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
default_parse_args(argc, argv);
doit(FALSE);
doit(TRUE);
return 0;
......
#ident "$Id: test-del-inorder.c 32975 2011-07-11 23:42:51Z leifwalsh $"
/* The goal of this test. Make sure that inserts stay behind deletes. */
#include "test.h"
#include "includes.h"
#include <brt-cachetable-wrappers.h>
#include "brt-flusher.h"
#include "brt-flusher-internal.h"
#include "checkpoint.h"
static TOKUTXN const null_txn = 0;
static DB * const null_db = 0;
enum { NODESIZE = 1024, KSIZE=NODESIZE-100, TOKU_PSIZE=20 };
CACHETABLE ct;
BRT t;
BOOL checkpoint_called;
BOOL checkpoint_callback_called;
toku_pthread_t checkpoint_tid;
// callback functions for flush_some_child
static bool
dont_destroy_bn(void* UU(extra))
{
return false;
}
static void merge_should_not_happen(struct flusher_advice* UU(fa),
struct brt_header* UU(h),
BRTNODE UU(parent),
int UU(childnum),
BRTNODE UU(child),
void* UU(extra))
{
assert(FALSE);
}
static bool recursively_flush_should_not_happen(BRTNODE UU(child), void* UU(extra)) {
assert(FALSE);
}
static int child_to_flush(struct brt_header* UU(h), BRTNODE parent, void* UU(extra)) {
assert(parent->height == 1);
assert(parent->n_children == 1);
return 0;
}
static void dummy_update_status(BRTNODE UU(child), int UU(dirtied), void* UU(extra)) {
}
static void checkpoint_callback(void* UU(extra)) {
usleep(1*1024*1024);
checkpoint_callback_called = TRUE;
}
static void *do_checkpoint(void *arg) {
// first verify that checkpointed_data is correct;
if (verbose) printf("starting a checkpoint\n");
int r = toku_checkpoint(ct, NULL, checkpoint_callback, NULL, NULL, NULL, CLIENT_CHECKPOINT);
assert_zero(r);
if (verbose) printf("completed a checkpoint\n");
return arg;
}
static void flusher_callback(int state, void* extra) {
BOOL after_split = *(BOOL *)extra;
if (verbose) {
printf("state %d\n", state);
}
if ((state == ft_flush_before_split && !after_split) ||
(state == ft_flush_during_split && after_split)) {
checkpoint_called = TRUE;
int r = toku_pthread_create(&checkpoint_tid, NULL, do_checkpoint, NULL);
assert_zero(r);
while (!checkpoint_callback_called) {
usleep(1*1024*1024);
}
}
}
static void
doit (BOOL after_split) {
BLOCKNUM node_leaf, node_root;
int r;
checkpoint_called = FALSE;
checkpoint_callback_called = FALSE;
toku_flusher_thread_set_callback(flusher_callback, &after_split);
r = toku_brt_create_cachetable(&ct, 500*1024*1024, ZERO_LSN, NULL_LOGGER); assert(r==0);
unlink("foo.brt");
unlink("bar.brt");
// note the basement node size is 5 times the node size
// this is done to avoid rebalancing when writing a leaf
// node to disk
r = toku_open_brt("foo.brt", 1, &t, NODESIZE, 5*NODESIZE, ct, null_txn, toku_builtin_compare_fun, null_db);
assert(r==0);
toku_testsetup_initialize(); // must precede any other toku_testsetup calls
r = toku_testsetup_leaf(t, &node_leaf, 1, NULL, NULL);
assert(r==0);
r = toku_testsetup_nonleaf(t, 1, &node_root, 1, &node_leaf, 0, 0);
assert(r==0);
r = toku_testsetup_root(t, node_root);
assert(r==0);
char dummy_val[NODESIZE-50];
memset(dummy_val, 0, sizeof(dummy_val));
r = toku_testsetup_insert_to_leaf(
t,
node_leaf,
"a",
2,
dummy_val,
sizeof(dummy_val)
);
assert_zero(r);
r = toku_testsetup_insert_to_leaf(
t,
node_leaf,
"z",
2,
dummy_val,
sizeof(dummy_val)
);
assert_zero(r);
// at this point, we have inserted two leafentries into
// the leaf, that should be big enough such that a split
// will happen
struct flusher_advice fa;
flusher_advice_init(
&fa,
child_to_flush,
dont_destroy_bn,
recursively_flush_should_not_happen,
merge_should_not_happen,
dummy_update_status,
default_pick_child_after_split,
NULL
);
BRTNODE node = NULL;
struct brtnode_fetch_extra bfe;
fill_bfe_for_min_read(&bfe, t->h);
toku_pin_brtnode_off_client_thread(
t->h,
node_root,
toku_cachetable_hash(t->h->cf, node_root),
&bfe,
0,
NULL,
&node
);
assert(node->height == 1);
assert(node->n_children == 1);
// do the flush
flush_some_child(t->h, node, &fa);
assert(checkpoint_callback_called);
// now let's pin the root again and make sure it is has split
toku_pin_brtnode_off_client_thread(
t->h,
node_root,
toku_cachetable_hash(t->h->cf, node_root),
&bfe,
0,
NULL,
&node
);
assert(node->height == 1);
assert(node->n_children == 2);
toku_unpin_brtnode(t, node);
void *ret;
r = toku_pthread_join(checkpoint_tid, &ret);
assert_zero(r);
//
// now the dictionary has been checkpointed
// copy the file to something with a new name,
// open it, and verify that the state of what is
// checkpointed is what we expect
//
r = system("cp foo.brt bar.brt ");
assert_zero(r);
BRT c_brt;
// note the basement node size is 5 times the node size
// this is done to avoid rebalancing when writing a leaf
// node to disk
r = toku_open_brt("bar.brt", 0, &c_brt, NODESIZE, 5*NODESIZE, ct, null_txn, toku_builtin_compare_fun, null_db);
assert(r==0);
//
// now pin the root, verify that we have a message in there, and that it is clean
//
fill_bfe_for_full_read(&bfe, c_brt->h);
toku_pin_brtnode_off_client_thread(
c_brt->h,
node_root,
toku_cachetable_hash(c_brt->h->cf, node_root),
&bfe,
0,
NULL,
&node
);
assert(node->height == 1);
assert(!node->dirty);
BLOCKNUM left_child, right_child;
if (after_split) {
assert(node->n_children == 2);
left_child = BP_BLOCKNUM(node,0);
assert(left_child.b == node_leaf.b);
right_child = BP_BLOCKNUM(node,1);
}
else {
assert(node->n_children == 1);
left_child = BP_BLOCKNUM(node,0);
assert(left_child.b == node_leaf.b);
}
toku_unpin_brtnode_off_client_thread(c_brt->h, node);
// now let's verify the leaves are what we expect
if (after_split) {
toku_pin_brtnode_off_client_thread(
c_brt->h,
left_child,
toku_cachetable_hash(c_brt->h->cf, left_child),
&bfe,
0,
NULL,
&node
);
assert(node->height == 0);
assert(!node->dirty);
assert(node->n_children == 1);
assert(toku_omt_size(BLB_BUFFER(node,0)) == 1);
toku_unpin_brtnode_off_client_thread(c_brt->h, node);
toku_pin_brtnode_off_client_thread(
c_brt->h,
right_child,
toku_cachetable_hash(c_brt->h->cf, right_child),
&bfe,
0,
NULL,
&node
);
assert(node->height == 0);
assert(!node->dirty);
assert(node->n_children == 1);
assert(toku_omt_size(BLB_BUFFER(node,0)) == 1);
toku_unpin_brtnode_off_client_thread(c_brt->h, node);
}
else {
toku_pin_brtnode_off_client_thread(
c_brt->h,
left_child,
toku_cachetable_hash(c_brt->h->cf, left_child),
&bfe,
0,
NULL,
&node
);
assert(node->height == 0);
assert(!node->dirty);
assert(node->n_children == 1);
assert(toku_omt_size(BLB_BUFFER(node,0)) == 2);
toku_unpin_brtnode_off_client_thread(c_brt->h, node);
}
DBT k;
struct check_pair pair1 = {2, "a", sizeof(dummy_val), dummy_val, 0};
r = toku_brt_lookup(c_brt, toku_fill_dbt(&k, "a", 2), lookup_checkf, &pair1);
assert(r==0);
struct check_pair pair2 = {2, "z", sizeof(dummy_val), dummy_val, 0};
r = toku_brt_lookup(c_brt, toku_fill_dbt(&k, "z", 2), lookup_checkf, &pair2);
assert(r==0);
r = toku_close_brt(t, 0); assert(r==0);
r = toku_close_brt(c_brt, 0); assert(r==0);
r = toku_cachetable_close(&ct); assert(r==0);
}
int
test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
default_parse_args(argc, argv);
doit(FALSE);
doit(TRUE);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment