#ident "Copyright (c) 2007 Tokutek Inc. All rights reserved." #include "includes.h" //typedef struct value *OMTVALUE; typedef OMTVALUE TESTVALUE; /* Things that would go in a omt-tests.h if we split to multiple files later. */ int verbose=0; #define CKERR(r) ({ if (r!=0) fprintf(stderr, "%s:%d error %d %s\n", __FILE__, __LINE__, r, strerror(r)); assert(r==0); }) #define CKERR2(r,r2) ({ if (r!=r2) fprintf(stderr, "%s:%d error %d %s, expected %d\n", __FILE__, __LINE__, r, strerror(r), r2); assert(r==r2); }) #define CKERR2s(r,r2,r3) ({ if (r!=r2 && r!=r3) fprintf(stderr, "%s:%d error %d %s, expected %d or %d\n", __FILE__, __LINE__, r, strerror(r), r2,r3); assert(r==r2||r==r3); }) #include 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 { u_int32_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 { BATCH_INSERT, INSERT_AT, INSERT_AT_ALMOST_RANDOM, }; /* Globals */ OMT omt; TESTVALUE* values = NULL; struct value* nums = NULL; u_int32_t length; static void cleanup_globals (void) { assert(values); toku_free(values); values = NULL; assert(nums); toku_free(nums); nums = NULL; } const unsigned int random_seed = 0xFEADACBA; static void init_init_values (unsigned int seed, u_int32_t num_elements) { srandom(seed); cleanup_globals(); MALLOC_N(num_elements, values); assert(values); MALLOC_N(num_elements, nums); assert(nums); length = num_elements; } static void init_identity_values (unsigned int seed, u_int32_t num_elements) { u_int32_t i; init_init_values(seed, num_elements); for (i = 0; i < length; i++) { nums[i].number = i; values[i] = (TESTVALUE)&nums[i]; } } static void init_distinct_sorted_values (unsigned int seed, u_int32_t num_elements) { u_int32_t i; init_init_values(seed, num_elements); u_int32_t number = 0; for (i = 0; i < length; i++) { number += (u_int32_t)(random() % 32) + 1; nums[i].number = number; values[i] = (TESTVALUE)&nums[i]; } } static void init_distinct_random_values (unsigned int seed, u_int32_t num_elements) { init_distinct_sorted_values(seed, num_elements); u_int32_t i; u_int32_t choice; u_int32_t choices; struct value temp; for (i = 0; i < length - 1; i++) { choices = length - i; choice = random() % choices; if (choice != i) { temp = nums[i]; nums[i] = nums[choice]; nums[choice] = temp; } } } static void init_globals (void) { MALLOC_N(1, values); assert(values); MALLOC_N(1, nums); assert(nums); 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); toku_omt_destroy(&omt); assert(omt==NULL); } static void test_create (enum close_when_done do_close) { int r; omt = NULL; r = toku_omt_create(&omt); CKERR(r); assert(omt!=NULL); test_close(do_close); } static void test_create_size (enum close_when_done do_close) { test_create(KEEP_WHEN_DONE); assert(toku_omt_size(omt) == 0); test_close(do_close); } static void test_create_insert_at_almost_random (enum close_when_done do_close) { u_int32_t i; int r; u_int32_t size = 0; test_create(KEEP_WHEN_DONE); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+1); CKERR2(r, EINVAL); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+2); CKERR2(r, EINVAL); for (i = 0; i < length/2; i++) { assert(size==toku_omt_size(omt)); r = toku_omt_insert_at(omt, values[i], i); CKERR(r); assert(++size==toku_omt_size(omt)); r = toku_omt_insert_at(omt, values[length-1-i], i+1); CKERR(r); assert(++size==toku_omt_size(omt)); } r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+1); CKERR2(r, EINVAL); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+2); CKERR2(r, EINVAL); assert(size==toku_omt_size(omt)); test_close(do_close); } static void test_create_insert_at_sequential (enum close_when_done do_close) { u_int32_t i; int r; u_int32_t size = 0; test_create(KEEP_WHEN_DONE); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+1); CKERR2(r, EINVAL); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+2); CKERR2(r, EINVAL); for (i = 0; i < length; i++) { assert(size==toku_omt_size(omt)); r = toku_omt_insert_at(omt, values[i], i); CKERR(r); assert(++size==toku_omt_size(omt)); } r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+1); CKERR2(r, EINVAL); r = toku_omt_insert_at(omt, values[0], toku_omt_size(omt)+2); CKERR2(r, EINVAL); assert(size==toku_omt_size(omt)); test_close(do_close); } static void test_create_from_sorted_array (enum create_type create_choice, enum close_when_done do_close) { int r; omt = NULL; if (create_choice == BATCH_INSERT) { r = toku_omt_create_from_sorted_array(&omt, values, length); CKERR(r); } 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(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(toku_omt_size(omt)==length); test_close(do_close); } static void test_fetch_verify (OMT omtree, TESTVALUE* val, u_int32_t len ) { u_int32_t i; int j; int r; TESTVALUE v = (TESTVALUE)&i; TESTVALUE oldv = v; OMTCURSOR c; r = toku_omt_cursor_create(&c); CKERR(r); assert(len == toku_omt_size(omtree)); for (i = 0; i < len; i++) { assert(oldv!=val[i]); v = NULL; r = toku_omt_fetch(omtree, i, &v, NULL); CKERR(r); assert(v != NULL); assert(v != oldv); assert(v == val[i]); assert(V(v)->number == V(val[i])->number); v = oldv; r = toku_omt_fetch(omtree, i, &v, c); CKERR(r); assert(v != NULL); assert(v != oldv); assert(v == val[i]); assert(V(v)->number == V(val[i])->number); assert(toku_omt_cursor_is_valid(c)); v = oldv; r = toku_omt_cursor_current(c, &v); CKERR(r); assert(v != NULL); assert(v != oldv); assert(v == val[i]); assert(V(v)->number == V(val[i])->number); assert(toku_omt_cursor_is_valid(c)); v = oldv; j = i + 1; while ((r = toku_omt_cursor_next(c, &v)) == 0) { assert(toku_omt_cursor_is_valid(c)); assert(v != NULL); assert(v != oldv); assert(v == val[j]); assert(V(v)->number == V(val[j])->number); j++; v = oldv; } CKERR2(r, EINVAL); assert(j == (int) len); assert(oldv!=val[i]); v = NULL; r = toku_omt_fetch(omtree, i, &v, c); CKERR(r); assert(v != NULL); assert(v != oldv); assert(v == val[i]); assert(V(v)->number == V(val[i])->number); v = oldv; j = i - 1; while ((r = toku_omt_cursor_prev(c, &v)) == 0) { assert(toku_omt_cursor_is_valid(c)); assert(v != NULL); assert(v != oldv); assert(v == val[j]); assert(V(v)->number == V(val[j])->number); j--; v = oldv; } CKERR2(r, EINVAL); assert(j == -1); } for (i = len; i < len*2; i++) { v = oldv; r = toku_omt_fetch(omtree, i, &v, NULL); CKERR2(r, EINVAL); assert(v == oldv); v = NULL; r = toku_omt_fetch(omtree, i, &v, c); CKERR2(r, EINVAL); assert(v == NULL); } toku_omt_cursor_destroy(&c); } 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(omt, values, length); test_close(do_close); } static int iterate_helper_error_return = 1; static int iterate_helper (TESTVALUE v, u_int32_t idx, void* extra) { if (extra == NULL) return iterate_helper_error_return; TESTVALUE* vals = (TESTVALUE *)extra; assert(v != NULL); assert(v == vals[idx]); assert(V(v)->number == V(vals[idx])->number); return 0; } static void test_iterate_verify (OMT omtree, TESTVALUE* vals, u_int32_t len) { int r; iterate_helper_error_return = 0; r = toku_omt_iterate(omtree, iterate_helper, (void*)vals); CKERR(r); iterate_helper_error_return = 0xFEEDABBA; r = toku_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(omt, values, length); test_close(do_close); } static void permute_array (u_int32_t* arr, u_int32_t len) { // // create a permutation of 0...size-1 // u_int32_t i = 0; for (i = 0; i < len; i++) { arr[i] = i; } for (i = 0; i < len - 1; i++) { u_int32_t choices = len - i; u_int32_t choice = random() % choices; if (choice != i) { u_int32_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) { u_int32_t i = 0; struct value* old_nums = NULL; MALLOC_N(length, old_nums); assert(nums); u_int32_t* perm = NULL; MALLOC_N(length, perm); assert(perm); TESTVALUE* old_values = NULL; MALLOC_N(length, old_values); assert(old_values); permute_array(perm, length); // // These are going to be the new values // for (i = 0; i < length; i++) { old_nums[i] = nums[i]; old_values[i] = &old_nums[i]; values[i] = &old_nums[i]; } test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); int r; r = toku_omt_set_at (omt, values[0], length); CKERR2(r,EINVAL); r = toku_omt_set_at (omt, values[0], length+1); CKERR2(r,EINVAL); for (i = 0; i < length; i++) { u_int32_t choice = perm[i]; values[choice] = &nums[choice]; nums[choice].number = (u_int32_t)random(); r = toku_omt_set_at (omt, values[choice], choice); CKERR(r); test_iterate_verify(omt, values, length); test_fetch_verify(omt, values, length); } r = toku_omt_set_at (omt, values[0], length); CKERR2(r,EINVAL); r = toku_omt_set_at (omt, values[0], length+1); CKERR2(r,EINVAL); toku_free(perm); toku_free(old_values); toku_free(old_nums); test_close(do_close); } static int insert_helper (TESTVALUE value, void* extra_insert) { TESTVALUE 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) { u_int32_t i = 0; u_int32_t* perm = NULL; MALLOC_N(length, perm); assert(perm); permute_array(perm, length); test_create(KEEP_WHEN_DONE); int r; u_int32_t size = length; length = 0; while (length < size) { u_int32_t choice = perm[length]; TESTVALUE to_insert = &nums[choice]; u_int32_t idx = UINT32_MAX; assert(length==toku_omt_size(omt)); r = toku_omt_insert(omt, to_insert, insert_helper, to_insert, &idx); CKERR(r); assert(idx <= length); if (idx > 0) { assert(V(to_insert)->number > V(values[idx-1])->number); } if (idx < length) { assert(V(to_insert)->number < V(values[idx])->number); } length++; assert(length==toku_omt_size(omt)); /* Make room */ for (i = length-1; i > idx; i--) { values[i] = values[i-1]; } values[idx] = to_insert; test_fetch_verify(omt, values, length); test_iterate_verify(omt, values, length); idx = UINT32_MAX; r = toku_omt_insert(omt, to_insert, insert_helper, to_insert, &idx); CKERR2(r, DB_KEYEXIST); assert(idx < length); assert(V(values[idx])->number == V(to_insert)->number); assert(length==toku_omt_size(omt)); test_iterate_verify(omt, values, length); test_fetch_verify(omt, values, 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) { u_int32_t i = 0; int r = ENOSYS; test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); assert(length == toku_omt_size(omt)); r = toku_omt_delete_at(omt, length); CKERR2(r,EINVAL); assert(length == toku_omt_size(omt)); r = toku_omt_delete_at(omt, length+1); CKERR2(r,EINVAL); while (length > 0) { assert(length == toku_omt_size(omt)); u_int32_t index_to_delete = random()%length; r = toku_omt_delete_at(omt, index_to_delete); CKERR(r); for (i = index_to_delete+1; i < length; i++) { values[i-1] = values[i]; } length--; test_fetch_verify(omt, values, length); test_iterate_verify(omt, values, length); } assert(length == 0); assert(length == toku_omt_size(omt)); r = toku_omt_delete_at(omt, length); CKERR2(r, EINVAL); assert(length == toku_omt_size(omt)); r = toku_omt_delete_at(omt, 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; u_int32_t i = 0; OMT left_split = NULL; OMT right_split = NULL; test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); for (i = 0; i <= length; i++) { r = toku_omt_split_at(omt, &right_split, length+1); CKERR2(r,EINVAL); r = toku_omt_split_at(omt, &right_split, length+2); CKERR2(r,EINVAL); // // test successful split // r = toku_omt_split_at(omt, &right_split, i); CKERR(r); left_split = omt; omt = NULL; assert(toku_omt_size(left_split) == i); assert(toku_omt_size(right_split) == length - i); test_fetch_verify(left_split, values, i); test_iterate_verify(left_split, values, i); test_fetch_verify(right_split, &values[i], length - i); test_iterate_verify(right_split, &values[i], length - i); // // verify that new OMT's cannot do bad splits // r = toku_omt_split_at(left_split, &omt, i+1); CKERR2(r,EINVAL); assert(toku_omt_size(left_split) == i); assert(toku_omt_size(right_split) == length - i); r = toku_omt_split_at(left_split, &omt, i+2); CKERR2(r,EINVAL); assert(toku_omt_size(left_split) == i); assert(toku_omt_size(right_split) == length - i); r = toku_omt_split_at(right_split, &omt, length - i + 1); CKERR2(r,EINVAL); assert(toku_omt_size(left_split) == i); assert(toku_omt_size(right_split) == length - i); r = toku_omt_split_at(right_split, &omt, length - i + 1); CKERR2(r,EINVAL); assert(toku_omt_size(left_split) == i); assert(toku_omt_size(right_split) == length - i); // // test merge // r = toku_omt_merge(left_split,right_split,&omt); CKERR(r); left_split = NULL; right_split = NULL; assert(toku_omt_size(omt) == length); test_fetch_verify(omt, values, length); test_iterate_verify(omt, values, length); } test_close(do_close); } static void init_values (enum rand_type rand_choice) { const u_int32_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 { u_int32_t first_zero; u_int32_t first_pos; } h_extra; static int test_heaviside (OMTVALUE v_omt, void* x) { TESTVALUE v = (OMTVALUE) v_omt; h_extra* extra = (h_extra*)x; assert(v && x); assert(extra->first_zero <= extra->first_pos); u_int32_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, u_int32_t first_zero, u_int32_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, u_int32_t idx_expect, u_int32_t number_expect, BOOL cursor_valid) { u_int32_t idx = UINT32_MAX; u_int32_t old_idx = idx; TESTVALUE omt_val, omt_val_curs; OMTCURSOR c; int r; BOOL found; r = toku_omt_cursor_create(&c); CKERR(r); omt_val = NULL; if (dir == 0) { r = toku_omt_find_zero(omt, h, extra, &omt_val, &idx, c); } else { r = toku_omt_find( omt, h, extra, dir, &omt_val, &idx, c); } CKERR2(r, r_expect); if (idx_will_change) { assert(idx == idx_expect); } else { assert(idx == old_idx); } if (r == DB_NOTFOUND) { assert(omt_val == NULL); found = FALSE; } else { assert(V(omt_val)->number == number_expect); found = TRUE; } assert(!cursor_valid == !toku_omt_cursor_is_valid(c)); if (cursor_valid) { TESTVALUE tmp; assert(idx_will_change); omt_val_curs = NULL; r = toku_omt_cursor_current(c, &omt_val_curs); CKERR(r); assert(toku_omt_cursor_is_valid(c)); r = toku_omt_fetch(omt, idx, &tmp, NULL); CKERR(r); if (found) assert(tmp==omt_val); assert(omt_val_curs != NULL); assert(omt_val_curs == tmp); assert(V(omt_val_curs)->number == V(tmp)->number); if (found) assert(V(omt_val_curs)->number==number_expect); } toku_omt_cursor_invalidate(c); assert(!toku_omt_cursor_is_valid(c)); toku_omt_cursor_destroy(&c); /* Verify we can pass NULL value. */ omt_val = NULL; idx = old_idx; if (dir == 0) { r = toku_omt_find_zero(omt, h, extra, NULL, &idx, NULL); } else { r = toku_omt_find( omt, h, extra, dir, NULL, &idx, NULL); } 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 = toku_omt_find_zero(omt, h, extra, &omt_val, 0, NULL); } else { r = toku_omt_find( omt, h, extra, dir, &omt_val, 0, NULL); } 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 = toku_omt_find_zero(omt, h, extra, NULL, 0, NULL); } else { r = toku_omt_find( omt, h, extra, dir, NULL, 0, NULL); } 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, length, length); test_find_dir(-1, &extra, test_heaviside, 0, TRUE, length-1, 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, length, 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, 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, length/2, length); test_find_dir(-1, &extra, test_heaviside, 0, TRUE, length/2-1, 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, length/2, length/2, TRUE); /* 0...0+...+ C B */ heavy_extra(&extra, 0, length/2); test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, FALSE, 0, 0, FALSE); test_find_dir(+1, &extra, test_heaviside, 0, TRUE, length/2, length/2, TRUE); test_find_dir(0, &extra, test_heaviside, 0, TRUE, 0, 0, TRUE); /* -...-+...+ AB */ heavy_extra(&extra, length/2, length/2); test_find_dir(-1, &extra, test_heaviside, 0, TRUE, length/2-1, length/2-1, TRUE); test_find_dir(+1, &extra, test_heaviside, 0, TRUE, length/2, length/2, TRUE); test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, TRUE, length/2, length/2, FALSE); /* -...-0...0+...+ AC B */ heavy_extra(&extra, length/3, 2*length/3); test_find_dir(-1, &extra, test_heaviside, 0, TRUE, length/3-1, length/3-1, TRUE); test_find_dir(+1, &extra, test_heaviside, 0, TRUE, 2*length/3, 2*length/3, TRUE); test_find_dir(0, &extra, test_heaviside, 0, TRUE, length/3, length/3, TRUE); /* Cleanup */ test_close(do_close); } static void invalidate_callback_null (OMTCURSOR c, void *extra) { assert(c && !extra); } static void invalidate_callback_inc (OMTCURSOR c, void *extra) { assert(c); int *num = extra; (*num)++; } static void test_invalidate (enum create_type create_choice, BOOL set_callback, BOOL invalidate_callback) { init_identity_values(random_seed, 100); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); OMTCURSOR c; int invalidate_count = 0; int r = toku_omt_cursor_create(&c); if (set_callback || invalidate_callback) { toku_omt_cursor_set_invalidate_callback(c, invalidate_callback_inc, &invalidate_count); } if (invalidate_callback) { toku_omt_cursor_set_invalidate_callback(c, invalidate_callback_null, NULL); } OMTVALUE val; r = toku_omt_fetch(omt, 0, &val, c); CKERR(r); assert(toku_omt_cursor_is_valid(c)); assert(invalidate_count==0); r = toku_omt_cursor_prev(c, &val); CKERR2(r, EINVAL); assert(!toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==1); else assert(invalidate_count==0); r = toku_omt_cursor_prev(c, &val); CKERR2(r, EINVAL); assert(!toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==1); else assert(invalidate_count==0); r = toku_omt_fetch(omt, toku_omt_size(omt)-1, &val, c); CKERR(r); assert(toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==1); else assert(invalidate_count==0); r = toku_omt_cursor_prev(c, &val); CKERR(r); assert(toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==1); else assert(invalidate_count==0); r = toku_omt_cursor_next(c, &val); CKERR(r); assert(toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==1); else assert(invalidate_count==0); r = toku_omt_cursor_next(c, &val); CKERR2(r, EINVAL); assert(!toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==2); else assert(invalidate_count==0); r = toku_omt_fetch(omt, toku_omt_size(omt)-1, &val, c); CKERR(r); assert(toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==2); else assert(invalidate_count==0); test_close(CLOSE_WHEN_DONE); assert(!toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==3); else assert(invalidate_count==0); init_identity_values(random_seed, 100); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); r = toku_omt_fetch(omt, toku_omt_size(omt)-1, &val, c); CKERR(r); assert(toku_omt_cursor_is_valid(c)); if (set_callback && !invalidate_callback) assert(invalidate_count==3); else assert(invalidate_count==0); toku_omt_cursor_destroy(&c); if (set_callback && !invalidate_callback) assert(invalidate_count==4); else assert(invalidate_count==0); test_close(CLOSE_WHEN_DONE); if (set_callback && !invalidate_callback) assert(invalidate_count==4); else assert(invalidate_count==0); } 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); test_invalidate( create_choice, FALSE, FALSE); test_invalidate( create_choice, FALSE, TRUE); test_invalidate( create_choice, TRUE, FALSE); test_invalidate( create_choice, TRUE, TRUE); } int 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(INSERT_AT); runtests_create_choice(INSERT_AT_ALMOST_RANDOM); cleanup_globals(); return 0; }