/* -*- mode: C; c-basic-offset: 4 -*- */ #ident "Copyright (c) 2007-2011 Tokutek Inc. All rights reserved." #ident "$Id: test-merges-on-cleaner.c 38542 2012-01-06 14:06:23Z christianrober $" /* The goal of this test. Make sure that inserts stay behind deletes. */ #include "test.h" #include "includes.h" #include #include "ft-flusher.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; FT_HANDLE brt; int fnamelen; char *fname; static int update_func( DB* UU(db), const DBT* key, const DBT* old_val, const DBT* UU(extra), void (*set_val)(const DBT *new_val, void *set_extra), void *set_extra) { DBT new_val; assert(old_val->size > 0); if (verbose) { printf("applying update to %s\n", (char *)key->data); } toku_init_dbt(&new_val); set_val(&new_val, set_extra); return 0; } static void doit (void) { BLOCKNUM node_leaf[2]; BLOCKNUM node_internal, node_root; int r; fnamelen = strlen(__SRCFILE__) + 20; fname = toku_malloc(fnamelen); assert(fname!=0); snprintf(fname, fnamelen, "%s.ft_handle", __SRCFILE__); r = toku_create_cachetable(&ct, 500*1024*1024, ZERO_LSN, NULL_LOGGER); assert(r==0); unlink(fname); r = toku_open_ft_handle(fname, 1, &brt, NODESIZE, NODESIZE/2, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); toku_free(fname); brt->update_fun = update_func; brt->h->update_fun = update_func; toku_testsetup_initialize(); // must precede any other toku_testsetup calls r = toku_testsetup_leaf(brt, &node_leaf[0], 1, NULL, NULL); assert(r==0); r = toku_testsetup_leaf(brt, &node_leaf[1], 1, NULL, NULL); assert(r==0); char* pivots[1]; pivots[0] = toku_strdup("kkkkk"); int pivot_len = 6; r = toku_testsetup_nonleaf(brt, 1, &node_internal, 2, node_leaf, pivots, &pivot_len); assert(r==0); r = toku_testsetup_nonleaf(brt, 2, &node_root, 1, &node_internal, 0, 0); assert(r==0); r = toku_testsetup_root(brt, node_root); assert(r==0); // // at this point we have created a tree with a root, an internal node, // and two leaf nodes, the pivot being "kkkkk" // // now we insert a row into each leaf node r = toku_testsetup_insert_to_leaf ( brt, node_leaf[0], "a", // key 2, // keylen "aa", 3 ); assert(r==0); r = toku_testsetup_insert_to_leaf ( brt, node_leaf[1], "z", // key 2, // keylen "zz", 3 ); assert(r==0); // // now insert a bunch of dummy delete messages // into the internal node, to get its cachepressure size up // for (int i = 0; i < 100000; i++) { r = toku_testsetup_insert_to_nonleaf ( brt, node_internal, FT_DELETE_ANY, "jj", // this key does not exist, so its message application should be a no-op 3, NULL, 0 ); assert(r==0); } // // now insert a broadcast message into the root // r = toku_testsetup_insert_to_nonleaf ( brt, node_root, FT_UPDATE_BROADCAST_ALL, NULL, 0, NULL, 0 ); assert(r==0); // // now let us induce a clean on the internal node // FTNODE node; toku_pin_node_with_min_bfe(&node, node_leaf[1], brt); // hack to get merge going BLB_SEQINSERT(node, node->n_children-1) = FALSE; toku_unpin_ftnode(brt->h, node); // now do a lookup on one of the keys, this should bring a leaf node up to date DBT k; struct check_pair pair = {2, "a", 0, NULL, 0}; r = toku_ft_lookup(brt, toku_fill_dbt(&k, "a", 2), lookup_checkf, &pair); assert(r==0); struct ftnode_fetch_extra bfe; fill_bfe_for_min_read(&bfe, brt->h); toku_pin_ftnode_off_client_thread( brt->h, node_internal, toku_cachetable_hash(brt->h->cf, node_internal), &bfe, TRUE, 0, NULL, &node ); assert(node->n_children == 2); // we expect that this flushes its buffer, that // a merge is not done, and that the lookup // of values "a" and "z" still works r = toku_ftnode_cleaner_callback( node, node_internal, toku_cachetable_hash(brt->h->cf, node_internal), brt->h ); // verify that node_internal's buffer is empty fill_bfe_for_min_read(&bfe, brt->h); toku_pin_ftnode_off_client_thread( brt->h, node_internal, toku_cachetable_hash(brt->h->cf, node_internal), &bfe, TRUE, 0, NULL, &node ); // check that merge happened assert(node->n_children == 1); // check that buffers are empty assert(toku_bnc_nbytesinbuf(BNC(node, 0)) == 0); toku_unpin_ftnode_off_client_thread(brt->h, node); // // now run a checkpoint to get everything clean, // and to get the rebalancing to happen // r = toku_checkpoint(ct, NULL, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT); assert_zero(r); // check that lookups on the two keys is still good struct check_pair pair1 = {2, "a", 0, NULL, 0}; r = toku_ft_lookup(brt, toku_fill_dbt(&k, "a", 2), lookup_checkf, &pair1); assert(r==0); struct check_pair pair2 = {2, "z", 0, NULL, 0}; r = toku_ft_lookup(brt, toku_fill_dbt(&k, "z", 2), lookup_checkf, &pair2); assert(r==0); r = toku_close_ft_handle_nolsn(brt, 0); assert(r==0); r = toku_cachetable_close(&ct); assert(r==0); toku_free(pivots[0]); } int test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) { default_parse_args(argc, argv); doit(); return 0; }