diff options
Diffstat (limited to 'storage/tokudb/PerconaFT/util/tests/omt-test.cc')
-rw-r--r-- | storage/tokudb/PerconaFT/util/tests/omt-test.cc | 898 |
1 files changed, 898 insertions, 0 deletions
diff --git a/storage/tokudb/PerconaFT/util/tests/omt-test.cc b/storage/tokudb/PerconaFT/util/tests/omt-test.cc new file mode 100644 index 00000000000..0d2c08f5198 --- /dev/null +++ b/storage/tokudb/PerconaFT/util/tests/omt-test.cc @@ -0,0 +1,898 @@ +/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: +#ident "$Id$" +/*====== +This file is part of PerconaFT. + + +Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. + + PerconaFT is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, + as published by the Free Software Foundation. + + PerconaFT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. + +---------------------------------------- + + PerconaFT is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License, version 3, + as published by the Free Software Foundation. + + PerconaFT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. +======= */ + +#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." + +#include "test.h" + +#include <util/omt.h> + +static void +parse_args (int argc, const char *argv[]) { + const char *argv0=argv[0]; + while (argc>1) { + int resultcode=0; + if (strcmp(argv[1], "-v")==0) { + verbose++; + } else if (strcmp(argv[1], "-q")==0) { + verbose = 0; + } else if (strcmp(argv[1], "-h")==0) { + do_usage: + fprintf(stderr, "Usage:\n%s [-v|-h]\n", argv0); + exit(resultcode); + } else { + resultcode=1; + goto do_usage; + } + argc--; + argv++; + } +} +/* End ".h like" stuff. */ + +struct value { + uint32_t number; +}; +#define V(x) ((struct value *)(x)) + +enum rand_type { + TEST_RANDOM, + TEST_SORTED, + TEST_IDENTITY +}; +enum close_when_done { + CLOSE_WHEN_DONE, + KEEP_WHEN_DONE +}; +enum create_type { + STEAL_ARRAY, + BATCH_INSERT, + INSERT_AT, + INSERT_AT_ALMOST_RANDOM, +}; + +/* Globals */ +typedef void *OMTVALUE; +toku::omt<OMTVALUE> *global_omt; +OMTVALUE* global_values = NULL; +struct value* global_nums = NULL; +uint32_t global_length; + +static void +cleanup_globals (void) { + assert(global_values); + toku_free(global_values); + global_values = NULL; + assert(global_nums); + toku_free(global_nums); + global_nums = NULL; +} + +/* Some test wrappers */ +struct functor { + int (*f)(OMTVALUE, uint32_t, void *); + void *v; +}; +int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor); +int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor) { + return ftor->f(const_cast<OMTVALUE>(v), idx, ftor->v); +} +static int omt_iterate(toku::omt<void *> *omt, int (*f)(OMTVALUE, uint32_t, void*), void*v) { + struct functor ftor = { .f = f, .v = v }; + return omt->iterate<functor, call_functor>(&ftor); +} + +struct heftor { + int (*h)(OMTVALUE, void *v); + void *v; +}; +int call_heftor(const OMTVALUE &v, const heftor &htor); +int call_heftor(const OMTVALUE &v, const heftor &htor) { + return htor.h(const_cast<OMTVALUE>(v), htor.v); +} +static int omt_insert(toku::omt<void *> *omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, uint32_t *index) { + struct heftor htor = { .h = h, .v = v }; + return omt->insert<heftor, call_heftor>(value, htor, index); +} +static int omt_find_zero(toku::omt<void *> *V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, uint32_t *index) { + struct heftor htor = { .h = h, .v = extra }; + return V->find_zero<heftor, call_heftor>(htor, value, index); +} +static int omt_find(toku::omt<void *> *V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, uint32_t *index) { + struct heftor htor = { .h = h, .v = extra }; + return V->find<heftor, call_heftor>(htor, direction, value, index); +} +static int omt_split_at(toku::omt<void *> *omt, toku::omt<void *> **newomtp, uint32_t index) { + toku::omt<void *> *XMALLOC(newomt); + int r = omt->split_at(newomt, index); + if (r != 0) { + toku_free(newomt); + } else { + *newomtp = newomt; + } + return r; +} +static int omt_merge(toku::omt<void *> *leftomt, toku::omt<void *> *rightomt, toku::omt<void *> **newomtp) { + toku::omt<void *> *XMALLOC(newomt); + newomt->merge(leftomt, rightomt); + toku_free(leftomt); + toku_free(rightomt); + *newomtp = newomt; + return 0; +} + +const unsigned int random_seed = 0xFEADACBA; + +static void +init_init_values (unsigned int seed, uint32_t num_elements) { + srandom(seed); + + cleanup_globals(); + + XMALLOC_N(num_elements, global_values); + XMALLOC_N(num_elements, global_nums); + global_length = num_elements; +} + +static void +init_identity_values (unsigned int seed, uint32_t num_elements) { + uint32_t i; + + init_init_values(seed, num_elements); + + for (i = 0; i < global_length; i++) { + global_nums[i].number = i; + global_values[i] = (OMTVALUE)&global_nums[i]; + } +} + +static void +init_distinct_sorted_values (unsigned int seed, uint32_t num_elements) { + uint32_t i; + + init_init_values(seed, num_elements); + + uint32_t number = 0; + + for (i = 0; i < global_length; i++) { + number += (uint32_t)(random() % 32) + 1; + global_nums[i].number = number; + global_values[i] = (OMTVALUE)&global_nums[i]; + } +} + +static void +init_distinct_random_values (unsigned int seed, uint32_t num_elements) { + init_distinct_sorted_values(seed, num_elements); + + uint32_t i; + uint32_t choice; + uint32_t choices; + struct value temp; + for (i = 0; i < global_length - 1; i++) { + choices = global_length - i; + choice = random() % choices; + if (choice != i) { + temp = global_nums[i]; + global_nums[i] = global_nums[choice]; + global_nums[choice] = temp; + } + } +} + +static void +init_globals (void) { + XMALLOC_N(1, global_values); + XMALLOC_N(1, global_nums); + global_length = 1; +} + +static void +test_close (enum close_when_done do_close) { + if (do_close == KEEP_WHEN_DONE) { + return; + } + assert(do_close == CLOSE_WHEN_DONE); + global_omt->destroy(); + toku_free(global_omt); +} + +static void +test_create (enum close_when_done do_close) { + XMALLOC(global_omt); + global_omt->create(); + test_close(do_close); +} + +static void +test_create_size (enum close_when_done do_close) { + test_create(KEEP_WHEN_DONE); + assert(global_omt->size() == 0); + test_close(do_close); +} + +static void +test_create_insert_at_almost_random (enum close_when_done do_close) { + uint32_t i; + int r; + uint32_t size = 0; + + test_create(KEEP_WHEN_DONE); + r = global_omt->insert_at(global_values[0], global_omt->size()+1); + CKERR2(r, EINVAL); + r = global_omt->insert_at(global_values[0], global_omt->size()+2); + CKERR2(r, EINVAL); + for (i = 0; i < global_length/2; i++) { + assert(size==global_omt->size()); + r = global_omt->insert_at(global_values[i], i); + CKERR(r); + assert(++size==global_omt->size()); + r = global_omt->insert_at(global_values[global_length-1-i], i+1); + CKERR(r); + assert(++size==global_omt->size()); + } + r = global_omt->insert_at(global_values[0], global_omt->size()+1); + CKERR2(r, EINVAL); + r = global_omt->insert_at(global_values[0], global_omt->size()+2); + CKERR2(r, EINVAL); + assert(size==global_omt->size()); + test_close(do_close); +} + +static void +test_create_insert_at_sequential (enum close_when_done do_close) { + uint32_t i; + int r; + uint32_t size = 0; + + test_create(KEEP_WHEN_DONE); + r = global_omt->insert_at(global_values[0], global_omt->size()+1); + CKERR2(r, EINVAL); + r = global_omt->insert_at(global_values[0], global_omt->size()+2); + CKERR2(r, EINVAL); + for (i = 0; i < global_length; i++) { + assert(size==global_omt->size()); + r = global_omt->insert_at(global_values[i], i); + CKERR(r); + assert(++size==global_omt->size()); + } + r = global_omt->insert_at(global_values[0], global_omt->size()+1); + CKERR2(r, EINVAL); + r = global_omt->insert_at(global_values[0], global_omt->size()+2); + CKERR2(r, EINVAL); + assert(size==global_omt->size()); + test_close(do_close); +} + +static void +test_create_from_sorted_array (enum create_type create_choice, enum close_when_done do_close) { + global_omt = NULL; + + if (create_choice == BATCH_INSERT) { + XMALLOC(global_omt); + global_omt->create_from_sorted_array(global_values, global_length); + } + else if (create_choice == STEAL_ARRAY) { + XMALLOC(global_omt); + OMTVALUE* XMALLOC_N(global_length, values_copy); + memcpy(values_copy, global_values, global_length*sizeof(*global_values)); + global_omt->create_steal_sorted_array(&values_copy, global_length, global_length); + assert(values_copy==NULL); + } + else if (create_choice == INSERT_AT) { + test_create_insert_at_sequential(KEEP_WHEN_DONE); + } + else if (create_choice == INSERT_AT_ALMOST_RANDOM) { + test_create_insert_at_almost_random(KEEP_WHEN_DONE); + } + else { + assert(false); + } + + assert(global_omt!=NULL); + test_close(do_close); +} + +static void +test_create_from_sorted_array_size (enum create_type create_choice, enum close_when_done do_close) { + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + assert(global_omt->size()==global_length); + test_close(do_close); +} + +static void +test_fetch_verify (toku::omt<void *> *omtree, OMTVALUE* val, uint32_t len ) { + uint32_t i; + int r; + OMTVALUE v = (OMTVALUE)&i; + OMTVALUE oldv = v; + + assert(len == omtree->size()); + for (i = 0; i < len; i++) { + assert(oldv!=val[i]); + v = NULL; + r = omtree->fetch(i, &v); + CKERR(r); + assert(v != NULL); + assert(v != oldv); + assert(v == val[i]); + assert(V(v)->number == V(val[i])->number); + v = oldv; + } + + for (i = len; i < len*2; i++) { + v = oldv; + r = omtree->fetch(i, &v); + CKERR2(r, EINVAL); + assert(v == oldv); + } + +} + +static void +test_create_fetch_verify (enum create_type create_choice, enum close_when_done do_close) { + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + test_fetch_verify(global_omt, global_values, global_length); + test_close(do_close); +} + +static int iterate_helper_error_return = 1; + +static int +iterate_helper (OMTVALUE v, uint32_t idx, void* extra) { + if (extra == NULL) return iterate_helper_error_return; + OMTVALUE* vals = (OMTVALUE *)extra; + assert(v != NULL); + assert(v == vals[idx]); + assert(V(v)->number == V(vals[idx])->number); + return 0; +} + +static void +test_iterate_verify (toku::omt<void *> *omtree, OMTVALUE* vals, uint32_t len) { + int r; + iterate_helper_error_return = 0; + r = omt_iterate(omtree, iterate_helper, (void*)vals); + CKERR(r); + iterate_helper_error_return = 0xFEEDABBA; + r = omt_iterate(omtree, iterate_helper, NULL); + if (!len) { + CKERR2(r, 0); + } + else { + CKERR2(r, iterate_helper_error_return); + } +} + +static void +test_create_iterate_verify (enum create_type create_choice, enum close_when_done do_close) { + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + test_iterate_verify(global_omt, global_values, global_length); + test_close(do_close); +} + + +static void +permute_array (uint32_t* arr, uint32_t len) { + // + // create a permutation of 0...size-1 + // + uint32_t i = 0; + for (i = 0; i < len; i++) { + arr[i] = i; + } + for (i = 0; i < len - 1; i++) { + uint32_t choices = len - i; + uint32_t choice = random() % choices; + if (choice != i) { + uint32_t temp = arr[i]; + arr[i] = arr[choice]; + arr[choice] = temp; + } + } +} + +static void +test_create_set_at (enum create_type create_choice, enum close_when_done do_close) { + uint32_t i = 0; + + struct value* old_nums = NULL; + XMALLOC_N(global_length, old_nums); + + uint32_t* perm = NULL; + XMALLOC_N(global_length, perm); + + OMTVALUE* old_values = NULL; + XMALLOC_N(global_length, old_values); + + permute_array(perm, global_length); + + // + // These are going to be the new global_values + // + for (i = 0; i < global_length; i++) { + old_nums[i] = global_nums[i]; + old_values[i] = &old_nums[i]; + global_values[i] = &old_nums[i]; + } + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + int r; + r = global_omt->set_at(global_values[0], global_length); + CKERR2(r,EINVAL); + r = global_omt->set_at(global_values[0], global_length+1); + CKERR2(r,EINVAL); + for (i = 0; i < global_length; i++) { + uint32_t choice = perm[i]; + global_values[choice] = &global_nums[choice]; + global_nums[choice].number = (uint32_t)random(); + r = global_omt->set_at(global_values[choice], choice); + CKERR(r); + test_iterate_verify(global_omt, global_values, global_length); + test_fetch_verify(global_omt, global_values, global_length); + } + r = global_omt->set_at(global_values[0], global_length); + CKERR2(r,EINVAL); + r = global_omt->set_at(global_values[0], global_length+1); + CKERR2(r,EINVAL); + + toku_free(perm); + toku_free(old_values); + toku_free(old_nums); + + test_close(do_close); +} + +static int +insert_helper (OMTVALUE value, void* extra_insert) { + OMTVALUE to_insert = (OMTVALUE)extra_insert; + assert(to_insert); + + if (V(value)->number < V(to_insert)->number) return -1; + if (V(value)->number > V(to_insert)->number) return +1; + return 0; +} + +static void +test_create_insert (enum close_when_done do_close) { + uint32_t i = 0; + + uint32_t* perm = NULL; + XMALLOC_N(global_length, perm); + + permute_array(perm, global_length); + + test_create(KEEP_WHEN_DONE); + int r; + uint32_t size = global_length; + global_length = 0; + while (global_length < size) { + uint32_t choice = perm[global_length]; + OMTVALUE to_insert = &global_nums[choice]; + uint32_t idx = UINT32_MAX; + + assert(global_length==global_omt->size()); + r = omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx); + CKERR(r); + assert(idx <= global_length); + if (idx > 0) { + assert(V(to_insert)->number > V(global_values[idx-1])->number); + } + if (idx < global_length) { + assert(V(to_insert)->number < V(global_values[idx])->number); + } + global_length++; + assert(global_length==global_omt->size()); + /* Make room */ + for (i = global_length-1; i > idx; i--) { + global_values[i] = global_values[i-1]; + } + global_values[idx] = to_insert; + test_fetch_verify(global_omt, global_values, global_length); + test_iterate_verify(global_omt, global_values, global_length); + + idx = UINT32_MAX; + r = omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx); + CKERR2(r, DB_KEYEXIST); + assert(idx < global_length); + assert(V(global_values[idx])->number == V(to_insert)->number); + assert(global_length==global_omt->size()); + + test_iterate_verify(global_omt, global_values, global_length); + test_fetch_verify(global_omt, global_values, global_length); + } + + toku_free(perm); + + test_close(do_close); +} + +static void +test_create_delete_at (enum create_type create_choice, enum close_when_done do_close) { + uint32_t i = 0; + int r = ENOSYS; + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + + assert(global_length == global_omt->size()); + r = global_omt->delete_at(global_length); + CKERR2(r,EINVAL); + assert(global_length == global_omt->size()); + r = global_omt->delete_at(global_length+1); + CKERR2(r,EINVAL); + while (global_length > 0) { + assert(global_length == global_omt->size()); + uint32_t index_to_delete = random()%global_length; + r = global_omt->delete_at(index_to_delete); + CKERR(r); + for (i = index_to_delete+1; i < global_length; i++) { + global_values[i-1] = global_values[i]; + } + global_length--; + test_fetch_verify(global_omt, global_values, global_length); + test_iterate_verify(global_omt, global_values, global_length); + } + assert(global_length == 0); + assert(global_length == global_omt->size()); + r = global_omt->delete_at(global_length); + CKERR2(r, EINVAL); + assert(global_length == global_omt->size()); + r = global_omt->delete_at(global_length+1); + CKERR2(r, EINVAL); + test_close(do_close); +} + +static void +test_split_merge (enum create_type create_choice, enum close_when_done do_close) { + int r = ENOSYS; + uint32_t i = 0; + toku::omt<void *> *left_split = NULL; + toku::omt<void *> *right_split = NULL; + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + + for (i = 0; i <= global_length; i++) { + r = omt_split_at(global_omt, &right_split, global_length+1); + CKERR2(r,EINVAL); + r = omt_split_at(global_omt, &right_split, global_length+2); + CKERR2(r,EINVAL); + + // + // test successful split + // + r = omt_split_at(global_omt, &right_split, i); + CKERR(r); + left_split = global_omt; + global_omt = NULL; + assert(left_split->size() == i); + assert(right_split->size() == global_length - i); + test_fetch_verify(left_split, global_values, i); + test_iterate_verify(left_split, global_values, i); + test_fetch_verify(right_split, &global_values[i], global_length - i); + test_iterate_verify(right_split, &global_values[i], global_length - i); + // + // verify that new global_omt's cannot do bad splits + // + r = omt_split_at(left_split, &global_omt, i+1); + CKERR2(r,EINVAL); + assert(left_split->size() == i); + assert(right_split->size() == global_length - i); + r = omt_split_at(left_split, &global_omt, i+2); + CKERR2(r,EINVAL); + assert(left_split->size() == i); + assert(right_split->size() == global_length - i); + r = omt_split_at(right_split, &global_omt, global_length - i + 1); + CKERR2(r,EINVAL); + assert(left_split->size() == i); + assert(right_split->size() == global_length - i); + r = omt_split_at(right_split, &global_omt, global_length - i + 1); + CKERR2(r,EINVAL); + assert(left_split->size() == i); + assert(right_split->size() == global_length - i); + + // + // test merge + // + r = omt_merge(left_split,right_split,&global_omt); + CKERR(r); + left_split = NULL; + right_split = NULL; + assert(global_omt->size() == global_length); + test_fetch_verify(global_omt, global_values, global_length); + test_iterate_verify(global_omt, global_values, global_length); + } + test_close(do_close); +} + + +static void +init_values (enum rand_type rand_choice) { + const uint32_t test_size = 100; + if (rand_choice == TEST_RANDOM) { + init_distinct_random_values(random_seed, test_size); + } + else if (rand_choice == TEST_SORTED) { + init_distinct_sorted_values(random_seed, test_size); + } + else if (rand_choice == TEST_IDENTITY) { + init_identity_values( random_seed, test_size); + } + else assert(false); +} + +static void +test_create_array (enum create_type create_choice, enum rand_type rand_choice) { + /* ********************************************************************** */ + init_values(rand_choice); + test_create_from_sorted_array( create_choice, CLOSE_WHEN_DONE); + test_create_from_sorted_array_size(create_choice, CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_create_fetch_verify( create_choice, CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_create_iterate_verify( create_choice, CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_create_set_at( create_choice, CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_create_delete_at( create_choice, CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_create_insert( CLOSE_WHEN_DONE); + /* ********************************************************************** */ + init_values(rand_choice); + test_split_merge( create_choice, CLOSE_WHEN_DONE); +} + +typedef struct { + uint32_t first_zero; + uint32_t first_pos; +} h_extra; + + +static int +test_heaviside (OMTVALUE v_omt, void* x) { + OMTVALUE v = (OMTVALUE) v_omt; + h_extra* extra = (h_extra*)x; + assert(v && x); + assert(extra->first_zero <= extra->first_pos); + + uint32_t value = V(v)->number; + if (value < extra->first_zero) return -1; + if (value < extra->first_pos) return 0; + return 1; +} + +static void +heavy_extra (h_extra* extra, uint32_t first_zero, uint32_t first_pos) { + extra->first_zero = first_zero; + extra->first_pos = first_pos; +} + +static void +test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*), + int r_expect, bool idx_will_change, uint32_t idx_expect, + uint32_t number_expect, bool UU(cursor_valid)) { + uint32_t idx = UINT32_MAX; + uint32_t old_idx = idx; + OMTVALUE omt_val; + int r; + + omt_val = NULL; + + /* Verify we can pass NULL value. */ + omt_val = NULL; + idx = old_idx; + if (dir == 0) { + r = omt_find_zero(global_omt, h, extra, NULL, &idx); + } + else { + r = omt_find( global_omt, h, extra, dir, NULL, &idx); + } + CKERR2(r, r_expect); + if (idx_will_change) { + assert(idx == idx_expect); + } + else { + assert(idx == old_idx); + } + assert(omt_val == NULL); + + /* Verify we can pass NULL idx. */ + omt_val = NULL; + idx = old_idx; + if (dir == 0) { + r = omt_find_zero(global_omt, h, extra, &omt_val, 0); + } + else { + r = omt_find( global_omt, h, extra, dir, &omt_val, 0); + } + CKERR2(r, r_expect); + assert(idx == old_idx); + if (r == DB_NOTFOUND) { + assert(omt_val == NULL); + } + else { + assert(V(omt_val)->number == number_expect); + } + + /* Verify we can pass NULL both. */ + omt_val = NULL; + idx = old_idx; + if (dir == 0) { + r = omt_find_zero(global_omt, h, extra, NULL, 0); + } + else { + r = omt_find( global_omt, h, extra, dir, NULL, 0); + } + CKERR2(r, r_expect); + assert(idx == old_idx); + assert(omt_val == NULL); +} + +static void +test_find (enum create_type create_choice, enum close_when_done do_close) { + h_extra extra; + init_identity_values(random_seed, 100); + test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); + +/* + -...- + A +*/ + heavy_extra(&extra, global_length, global_length); + test_find_dir(-1, &extra, test_heaviside, 0, true, global_length-1, global_length-1, true); + test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, global_length, global_length, false); + + +/* + +...+ + B +*/ + heavy_extra(&extra, 0, 0); + test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(+1, &extra, test_heaviside, 0, true, 0, 0, true); + test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, 0, 0, false); + +/* + 0...0 + C +*/ + heavy_extra(&extra, 0, global_length); + test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true); + +/* + -...-0...0 + AC +*/ + heavy_extra(&extra, global_length/2, global_length); + test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/2-1, global_length/2-1, true); + test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(0, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true); + +/* + 0...0+...+ + C B +*/ + heavy_extra(&extra, 0, global_length/2); + test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); + test_find_dir(+1, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true); + test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true); + +/* + -...-+...+ + AB +*/ + heavy_extra(&extra, global_length/2, global_length/2); + test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/2-1, global_length/2-1, true); + test_find_dir(+1, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true); + test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, global_length/2, global_length/2, false); + +/* + -...-0...0+...+ + AC B +*/ + heavy_extra(&extra, global_length/3, 2*global_length/3); + test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/3-1, global_length/3-1, true); + test_find_dir(+1, &extra, test_heaviside, 0, true, 2*global_length/3, 2*global_length/3, true); + test_find_dir(0, &extra, test_heaviside, 0, true, global_length/3, global_length/3, true); + + /* Cleanup */ + test_close(do_close); +} + +static void +runtests_create_choice (enum create_type create_choice) { + test_create_array(create_choice, TEST_SORTED); + test_create_array(create_choice, TEST_RANDOM); + test_create_array(create_choice, TEST_IDENTITY); + test_find( create_choice, CLOSE_WHEN_DONE); +} + +static void +test_clone(uint32_t nelts) +// Test that each clone operation gives the right data back. If nelts is +// zero, also tests that you still get a valid omt back and that the way +// to deallocate it still works. +{ + toku::omt<void *> *src = NULL, *dest = NULL; + int r; + + XMALLOC(src); + src->create(); + for (long i = 0; i < nelts; ++i) { + r = src->insert_at((OMTVALUE) i, i); + assert_zero(r); + } + + XMALLOC(dest); + dest->clone(*src); + assert(dest != NULL); + assert(dest->size() == nelts); + for (long i = 0; i < nelts; ++i) { + OMTVALUE v; + long l; + r = dest->fetch(i, &v); + assert_zero(r); + l = (long) v; + assert(l == i); + } + dest->destroy(); + toku_free(dest); + src->destroy(); + toku_free(src); +} + +int +test_main(int argc, const char *argv[]) { + parse_args(argc, argv); + init_globals(); + test_create( CLOSE_WHEN_DONE); + test_create_size( CLOSE_WHEN_DONE); + runtests_create_choice(BATCH_INSERT); + runtests_create_choice(STEAL_ARRAY); + runtests_create_choice(INSERT_AT); + runtests_create_choice(INSERT_AT_ALMOST_RANDOM); + test_clone(0); + test_clone(1); + test_clone(1000); + test_clone(10000); + cleanup_globals(); + return 0; +} + |