/* -*- mode: C; c-basic-offset: 4 -*- */ #ident "Copyright (c) 2007 Tokutek Inc. All rights reserved." #include "brt-internal.h" #include "key.h" #include #include #include #include #include #include "list.h" #include "pma-internal.h" static TOKUTXN const null_txn = 0; static DB * const null_db = 0; static const DISKOFF null_diskoff = -1; static const FILENUM null_filenum = {0}; #define NULL_ARGS null_txn, null_filenum, null_diskoff void *skey=0, *sval=0; void local_memory_check_all_free(void) { if (skey) toku_free(skey); if (sval) toku_free(sval); skey = sval = 0; toku_memory_check_all_free(); } static void test_make_space_at (void) { PMA pma; char *key; int r; unsigned int newi; struct kv_pair *key_A, *key_B; key = "A"; key_A = kv_pair_malloc(key, strlen(key)+1, 0, 0); key = "B"; key_B = kv_pair_malloc(key, strlen(key)+1, 0, 0); r=toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); assert(toku_pma_n_entries(pma)==0); r=toku_pmainternal_make_space_at(null_txn, null_filenum, null_diskoff, pma, 2, &newi); assert(r==0); assert(toku_pma_index_limit(pma)==4); assert((unsigned long)pma->pairs[toku_pma_index_limit(pma)]==0xdeadbeefL); toku_print_pma(pma); pma->pairs[2] = key_A; pma->n_pairs_present++; r=toku_pmainternal_make_space_at(null_txn, null_filenum, null_diskoff, pma, 2, &newi); assert(r==0); printf("Requested space at 2, got space at %d\n", newi); toku_print_pma(pma); assert(pma->pairs[newi]==0); assert((unsigned long)pma->pairs[toku_pma_index_limit(pma)]==0xdeadbeefL); assert(toku_pma_index_limit(pma)==4); pma->pairs[0] = key_A; pma->pairs[1] = key_B; pma->pairs[2] = 0; pma->pairs[3] = 0; pma->n_pairs_present=2; toku_print_pma(pma); toku_pmainternal_make_space_at(null_txn, null_filenum, null_diskoff, pma, 0, &newi); assert(r==0); printf("Requested space at 0, got space at %d\n", newi); toku_print_pma(pma); assert((unsigned long)pma->pairs[toku_pma_index_limit(pma)]==0xdeadbeefL); // make sure it doesn't go off the end. assert(toku_pma_index_limit(pma)==8); pma->pairs[0] = key_A; pma->pairs[1] = 0; pma->pairs[2] = 0; pma->pairs[3] = 0; pma->pairs[4] = key_B; pma->pairs[5] = 0; pma->pairs[6] = 0; pma->pairs[7] = 0; pma->n_pairs_present=2; toku_print_pma(pma); r=toku_pmainternal_make_space_at(null_txn, null_filenum, null_diskoff, pma, 5, &newi); assert(r==0); toku_print_pma(pma); printf("r=%d\n", newi); { unsigned int i; for (i=0; ipairs[i]) { assert(ipairs[i] = 0; } } } pma->n_pairs_present = 0; r=toku_pma_free(&pma); assert(r==0); assert(pma==0); kv_pair_free(key_A); kv_pair_free(key_B); } static void test_pma_find (void) { PMA pma; unsigned int i, fidx; int r; const unsigned int N = 16; DBT k; MALLOC(pma); MALLOC_N(N,pma->pairs); // All that is needed to test pma_find is N and pairs. pma->N = N; for (i=0; ipairs[i]=0; assert(toku_pma_index_limit(pma)==N); pma->compare_fun = toku_default_compare_fun; r=toku_pmainternal_find(pma, toku_fill_dbt(&k, "hello", 5)); assert(r==0); pma->pairs[5] = kv_pair_malloc("hello", 5, 0, 0); assert(toku_pma_index_limit(pma)==N); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "hello", 5)); assert(toku_pma_index_limit(pma)==N); assert(fidx==5); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "there", 5)); assert(fidx==6); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "aaa", 3)); assert(fidx==0); pma->pairs[N-1] = kv_pair_malloc("there", 5, 0, 0); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "hello", 5)); assert(fidx==5); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "there", 5)); assert(fidx+1==N); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "aaa", 3)); assert(fidx==0); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "hellob", 6)); assert(fidx==6); fidx=toku_pmainternal_find(pma, toku_fill_dbt(&k, "zzz", 3)); assert(fidx==N); for (i=0; ipairs[i]) kv_pair_free(pma->pairs[i]); toku_free(pma->pairs); toku_free(pma); } static void test_smooth_region_N (int N) { struct kv_pair *pairs[N]; struct kv_pair *strings[N]; char string[N]; int i; int len; if (N<10) len=1; else if (N<100) len=2; else len=8; for (i=0; ikey); assert(cleari&(1<r); } } assert(cleari==0); } } } for (i=0; ikey : "?"); printf("} %d\n", r); for (i=0; i<7; i++) if (pairs[i]) kv_pair_free(pairs[i]); } static void test_smooth_region (void) { test_smooth_region_N(4); test_smooth_region_N(5); test_smooth_region6(); } static void test_calculate_parameters (void) { struct pma pma; pma.N=4; toku_pmainternal_calculate_parameters(&pma); assert(pma.uplgN==2); assert(pma.udt_step==0.5); pma.N=8; toku_pmainternal_calculate_parameters(&pma); assert(pma.uplgN==4); assert(pma.udt_step==0.5); } static void test_count_region (void) { const int N = 4; struct kv_pair *pairs[N]; int i; char *key; for (i=0; ipairs[toku_pma_index_limit(pma)]==0xdeadbeefL); do_insert(pma, "00000", 6, "d0", 3, rand4fingerprint, &sum, &expect_fingerprint); assert((unsigned long)pma->pairs[toku_pma_index_limit(pma)]==0xdeadbeefL); r=toku_pma_free(&pma); assert(r==0); assert(pma==0); toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(pma!=0); rand4fingerprint = random(); sum = expect_fingerprint = 0; { int i; for (i=0; i<100; i++) { char string[10]; char dstring[10]; snprintf(string,10,"%05d",i); snprintf(dstring,10,"d%d", i); //printf("Inserting %d: string=%s dstring=%s (before sum=%08x) \n", i, string, dstring, sum); do_insert(pma, string, strlen(string)+1, dstring, strlen(dstring)+1, rand4fingerprint, &sum, &expect_fingerprint); } } r=toku_pma_free(&pma); assert(r==0); assert(pma==0); } static int tpi_k,tpi_v; static void do_sum_em (bytevec key, ITEMLEN keylen, bytevec val, ITEMLEN vallen, void *v) { assert((unsigned long)v==0xdeadbeefL); assert(strlen(key)+1==keylen); assert(strlen(val)+1==vallen); tpi_k += atoi(key); tpi_v += atoi(val); } static void test_pma_iterate_internal (PMA pma, int expected_k, int expected_v) { tpi_k=tpi_v=0; toku_pma_iterate(pma, do_sum_em, (void*)0xdeadbeefL); assert(tpi_k==expected_k); assert(tpi_v==expected_v); } static void test_pma_iterate (void) { PMA pma; int r; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); do_insert(pma, "42", 3, "-19", 4, rand4fingerprint, &sum, &expect_fingerprint); test_pma_iterate_internal(pma, 42, -19); do_insert(pma, "12", 3, "-100", 5, rand4fingerprint, &sum, &expect_fingerprint); test_pma_iterate_internal(pma, 42+12, -19-100); r=toku_pma_free(&pma); assert(r==0); assert(pma==0); } static void test_pma_iterate2 (void) { PMA pma0,pma1; int r; int sum=0; int n_items=0; u_int32_t rand4fingerprint0 = random(); u_int32_t sum0 = 0; u_int32_t expect_fingerprint0 = 0; u_int32_t rand4fingerprint1 = random(); u_int32_t sum1 = 0; u_int32_t expect_fingerprint1 = 0; r=toku_pma_create(&pma0, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); r=toku_pma_create(&pma1, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); do_insert(pma0, "a", 2, "aval", 5, rand4fingerprint0, &sum0, &expect_fingerprint0); do_insert(pma0, "b", 2, "bval", 5, rand4fingerprint0, &sum0, &expect_fingerprint0); do_insert(pma1, "x", 2, "xval", 5, rand4fingerprint1, &sum1, &expect_fingerprint1); PMA_ITERATE(pma0,kv __attribute__((__unused__)),kl,dv __attribute__((__unused__)),dl, (n_items++,sum+=kl+dl)); PMA_ITERATE(pma1,kv __attribute__((__unused__)),kl,dv __attribute__((__unused__)), dl, (n_items++,sum+=kl+dl)); assert(sum==21); assert(n_items==3); r=toku_pma_free(&pma0); assert(r==0); assert(pma0==0); r=toku_pma_free(&pma1); assert(r==0); assert(pma1==0); } /* Check to see if we can create and kill a cursor. */ static void test_pma_cursor_0 (void) { PMA pma; PMA_CURSOR c=0; int r; r=toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); r=toku_pma_cursor(pma, &c, &skey, &sval); assert(r==0); assert(c!=0); printf("%s:%d\n", __FILE__, __LINE__); r=toku_pma_free(&pma); assert(r!=0); /* didn't deallocate the cursor. */ printf("%s:%d\n", __FILE__, __LINE__); r=toku_pma_cursor_free(&c); assert(r==0); printf("%s:%d\n", __FILE__, __LINE__); r=toku_pma_free(&pma); assert(r==0); /* did deallocate the cursor. */ } /* Make sure we can free the cursors in any order. There is a doubly linked list of cursors * and if we free them in a different order, then different unlinking code is invoked. */ static void test_pma_cursor_1 (void) { PMA pma; PMA_CURSOR c0=0,c1=0,c2=0; int r; int order; for (order=0; order<6; order++) { r=toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); r=toku_pma_cursor(pma, &c0, &skey, &sval); assert(r==0); assert(c0!=0); r=toku_pma_cursor(pma, &c1, &skey, &sval); assert(r==0); assert(c1!=0); r=toku_pma_cursor(pma, &c2, &skey, &sval); assert(r==0); assert(c2!=0); r=toku_pma_free(&pma); assert(r!=0); if (order<2) { r=toku_pma_cursor_free(&c0); assert(r==0); c0=c1; c1=c2; } else if (order<4) { r=toku_pma_cursor_free(&c1); assert(r==0); c1=c2; } else { r=toku_pma_cursor_free(&c2); assert(r==0); } r=toku_pma_free(&pma); assert(r!=0); if (order%2==0) { r=toku_pma_cursor_free(&c0); assert(r==0); c0=c1; } else { r=toku_pma_cursor_free(&c1); assert(r==0); } r=toku_pma_free(&pma); assert(r!=0); r = toku_pma_cursor_free(&c0); assert(r==0); r=toku_pma_free(&pma); assert(r==0); } } static void test_pma_cursor_2 (void) { PMA pma; PMA_CURSOR c=0; int r; DBT key,val; toku_init_dbt(&key); key.flags=DB_DBT_REALLOC; toku_init_dbt(&val); val.flags=DB_DBT_REALLOC; r=toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); r=toku_pma_cursor(pma, &c, &skey, &sval); assert(r==0); assert(c!=0); r=toku_pma_cursor_set_position_last(c); assert(r==DB_NOTFOUND); r=toku_pma_cursor_free(&c); assert(r==0); r=toku_pma_free(&pma); assert(r==0); } static void test_pma_cursor_3 (void) { PMA pma; PMA_CURSOR c=0; int r; DBT key,val; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; r=toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); do_insert(pma, "x", 2, "xx", 3, rand4fingerprint, &sum, &expect_fingerprint); do_insert(pma, "m", 2, "mm", 3, rand4fingerprint, &sum, &expect_fingerprint); do_insert(pma, "aa", 3, "a", 2, rand4fingerprint, &sum, &expect_fingerprint); toku_init_dbt(&key); key.flags=DB_DBT_REALLOC; toku_init_dbt(&val); val.flags=DB_DBT_REALLOC; r=toku_pma_cursor(pma, &c, &skey, &sval); assert(r==0); assert(c!=0); r=toku_pma_cursor_set_position_first(c); assert(r==0); r=toku_pma_cursor_get_current(c, &key, &val, 0); assert(r==0); assert(key.size=3); assert(memcmp(key.data,"aa",3)==0); assert(val.size=2); assert(memcmp(val.data,"a",2)==0); r=toku_pma_cursor_set_position_next(c); assert(r==0); r=toku_pma_cursor_get_current(c, &key, &val, 0); assert(r==0); assert(key.size=2); assert(memcmp(key.data,"m",2)==0); assert(val.size=3); assert(memcmp(val.data,"mm",3)==0); r=toku_pma_cursor_set_position_next(c); assert(r==0); r=toku_pma_cursor_get_current(c, &key, &val, 0); assert(r==0); assert(key.size=2); assert(memcmp(key.data,"x",2)==0); assert(val.size=3); assert(memcmp(val.data,"xx",3)==0); r=toku_pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); /* After an error, the cursor should still point at the same thing. */ r=toku_pma_cursor_get_current(c, &key, &val, 0); assert(r==0); assert(key.size=2); assert(memcmp(key.data,"x",2)==0); assert(val.size=3); assert(memcmp(val.data,"xx",3)==0); r=toku_pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); toku_free(key.data); toku_free(val.data); r=toku_pma_cursor_free(&c); assert(r==0); r=toku_pma_free(&pma); assert(r==0); } static void assert_cursor_val(PMA_CURSOR cursor, int v) { DBT key, val; int error; toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_cursor_get_current(cursor, &key, &val, 0); assert(error == 0); assert( v == *(int *)val.data); toku_free(key.data); toku_free(val.data); } /* make sure cursors are adjusted when the pma grows */ static void test_pma_cursor_4 (void) { int error; PMA pma; PMA_CURSOR cursora, cursorb, cursorc; int i; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; printf("test_pma_cursor_4\n"); error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); for (i=1; i<=4; i += 1) { char k[5]; int v; sprintf(k, "%4.4d", i); v = i; do_insert(pma, k, strlen(k)+1, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } assert(toku_pma_n_entries(pma) == 4); printf("a:"); toku_print_pma(pma); error = toku_pma_cursor(pma, &cursora, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_first(cursora); assert(error == 0); assert_cursor_val(cursora, 1); error = toku_pma_cursor(pma, &cursorb, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_first(cursorb); assert(error == 0); assert_cursor_val(cursorb, 1); error = toku_pma_cursor_set_position_next(cursorb); assert(error == 0); assert_cursor_val(cursorb, 2); error = toku_pma_cursor(pma, &cursorc, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_last(cursorc); assert(error == 0); assert_cursor_val(cursorc, 4); for (i=5; i<=8; i += 1) { char k[5]; int v; sprintf(k, "%4.4d", i); v = i; do_insert(pma, k, strlen(k)+1, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } assert(toku_pma_n_entries(pma) == 8); printf("a:"); toku_print_pma(pma); assert_cursor_val(cursora, 1); assert_cursor_val(cursorb, 2); assert_cursor_val(cursorc, 4); error = toku_pma_cursor_free(&cursora); assert(error == 0); error = toku_pma_cursor_free(&cursorb); assert(error == 0); error = toku_pma_cursor_free(&cursorc); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_delete(int n) { printf("test_pma_cursor_delete:%d\n", n); PMA pma; int error; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); /* insert 1 -> 42 */ int k, v; int i; for (i=0; idata; unsigned char *bd=b->data; int siz = a->size; assert(a->size==b->size); // This function requires that the keys be the same size. for (i=0; isize; i++) { if (ad[siz-1-i]bd[siz-1-i]) return +1; } return 0; } static void test_pma_compare_fun (int wrong_endian_p) { PMA pma; PMA_CURSOR c = 0; DBT key,val; int r; char *wrong_endian_expected_keys[] = {"00", "10", "01", "11"}; /* Sorry for being judgemental. But it's wrong. */ char *right_endian_expected_keys[] = {"00", "01", "10", "11"}; char **expected_keys = wrong_endian_p ? wrong_endian_expected_keys : right_endian_expected_keys; int i; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; r = toku_pma_create(&pma, wrong_endian_p ? wrong_endian_compare_fun : toku_default_compare_fun, null_db, null_filenum, 0); assert(r==0); do_insert(pma, "10", 3, "10v", 4, rand4fingerprint, &sum, &expect_fingerprint); do_insert(pma, "00", 3, "00v", 4, rand4fingerprint, &sum, &expect_fingerprint); do_insert(pma, "01", 3, "01v", 4, rand4fingerprint, &sum, &expect_fingerprint); do_insert(pma, "11", 3, "11v", 4, rand4fingerprint, &sum, &expect_fingerprint); toku_init_dbt(&key); key.flags=DB_DBT_REALLOC; toku_init_dbt(&val); val.flags=DB_DBT_REALLOC; r=toku_pma_cursor(pma, &c, &skey, &sval); assert(r==0); assert(c!=0); for (i=0; i<4; i++) { if (i==0) { r=toku_pma_cursor_set_position_first(c); assert(r==0); } else { r=toku_pma_cursor_set_position_next(c); assert(r==0); } r=toku_pma_cursor_get_current(c, &key, &val, 0); assert(r==0); //printf("Got %s, expect %s\n", (char*)key.data, expected_keys[i]); assert(key.size=3); assert(memcmp(key.data,expected_keys[i],3)==0); assert(val.size=4); assert(memcmp(val.data,expected_keys[i],2)==0); assert(memcmp(2+(char*)val.data,"v",2)==0); } r=toku_pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); toku_free(key.data); toku_free(val.data); r=toku_pma_cursor_free(&c); assert(r==0); r=toku_pma_free(&pma); assert(r==0); } static void test_pma_split_n(int n) { PMA pmaa, pmab, pmac; int error; int i; int na, nb, nc; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; u_int32_t brand = random(); u_int32_t bsum = 0; u_int32_t crand = random(); u_int32_t csum = 0; printf("test_pma_split_n:%d\n", n); error = toku_pma_create(&pmaa, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmab, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmac, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); /* insert some kv pairs */ for (i=0; i 0) { int kk; assert(splitk.size == sizeof kk); memcpy(&kk, splitk.data, splitk.size); assert(kk == dupkey); if (nb > 0) assert(splitk.flags & BRT_PIVOT_PRESENT_L); if (nc > 0) assert(splitk.flags & BRT_PIVOT_PRESENT_R); } if (splitk.data) toku_free(splitk.data); assert(na == 0); assert(nb + nc == n); error = toku_pma_free(&pmaa); assert(error == 0); error = toku_pma_free(&pmab); assert(error == 0); error = toku_pma_free(&pmac); assert(error == 0); } static void test_pma_split_varkey(void) { char *keys[] = { "this", "is", "a", "key", "this is a really really big key", "zz", 0 }; PMA pmaa, pmab, pmac; int error; int i; int n, na, nb, nc; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; u_int32_t brand = random(); u_int32_t bsum = 0; u_int32_t crand = random(); u_int32_t csum = 0; printf("test_pma_split_varkey\n"); error = toku_pma_create(&pmaa, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmab, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmac, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); /* insert some kv pairs */ for (i=0; keys[i]; i++) { char v = i; do_insert(pmaa, keys[i], strlen(keys[i])+1, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } n = i; printf("a:"); toku_print_pma(pmaa); error = toku_pma_split(null_txn, null_filenum, pmaa, 0, 0, (DISKOFF)0, pmab, 0, brand, &bsum, (DISKOFF)0, pmac, 0, crand, &csum); assert(error == 0); toku_pma_verify(pmaa); toku_pma_verify(pmab); toku_pma_verify(pmac); toku_pma_verify_fingerprint(pmab, brand, bsum); toku_pma_verify_fingerprint(pmac, crand, csum); printf("a:"); toku_print_pma(pmaa); na = toku_pma_n_entries(pmaa); printf("b:"); toku_print_pma(pmab); nb = toku_pma_n_entries(pmab); printf("c:"); toku_print_pma(pmac); nc = toku_pma_n_entries(pmac); assert(na == 0); assert(nb + nc == n); error = toku_pma_free(&pmaa); assert(error == 0); error = toku_pma_free(&pmab); assert(error == 0); error = toku_pma_free(&pmac); assert(error == 0); } #if 0 static void print_cursor(const char *str, PMA_CURSOR cursor) { DBT key, val; int error; printf("cursor %s: ", str); toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_cursor_get_current(cursor, &key, &val, 0); assert(error == 0); printf("%s ", (char*)key.data); toku_free(key.data); toku_free(val.data); printf("\n"); } #endif static void walk_cursor(const char *str, PMA_CURSOR cursor) { DBT key, val; int error; printf("walk %s: ", str); for (;;) { toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_cursor_get_current(cursor, &key, &val, 0); assert(error == 0); printf("%s ", (char*)key.data); toku_free(key.data); toku_free(val.data); error = toku_pma_cursor_set_position_next(cursor); if (error != 0) break; } printf("\n"); } static void walk_cursor_reverse(const char *str, PMA_CURSOR cursor) { DBT key, val; int error; printf("walk %s: ", str); for (;;) { toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_cursor_get_current(cursor, &key, &val, 0); assert(error == 0); printf("%s ", (char*)key.data); toku_free(key.data); toku_free(val.data); error = toku_pma_cursor_set_position_prev(cursor); if (error != 0) break; } printf("\n"); } static void test_pma_split_cursor(void) { PMA pmaa, pmab, pmac; PMA_CURSOR cursora, cursorb, cursorc; int error; int i; int na, nb, nc; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; u_int32_t brand = random(); u_int32_t bsum = 0; u_int32_t crand = random(); u_int32_t csum = 0; printf("test_pma_split_cursor\n"); error = toku_pma_create(&pmaa, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmab, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); error = toku_pma_create(&pmac, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); /* insert some kv pairs */ for (i=1; i<=16; i += 1) { char k[11]; int v; snprintf(k, sizeof k, "%.10d", i); v = i; do_insert(pmaa, k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } assert(toku_pma_n_entries(pmaa) == 16); printf("a:"); toku_print_pma(pmaa); error = toku_pma_cursor(pmaa, &cursora, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_first(cursora); assert(error == 0); // print_cursor("cursora", cursora); assert_cursor_val(cursora, 1); error = toku_pma_cursor(pmaa, &cursorb, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_first(cursorb); assert(error == 0); error = toku_pma_cursor_set_position_next(cursorb); assert(error == 0); // print_cursor("cursorb", cursorb); assert_cursor_val(cursorb, 2); error = toku_pma_cursor(pmaa, &cursorc, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_last(cursorc); assert(error == 0); // print_cursor("cursorc", cursorc); assert_cursor_val(cursorc, 16); error = toku_pma_split(null_txn, null_filenum, pmaa, 0, 0, (DISKOFF)0, pmab, 0, brand, &bsum, (DISKOFF)0, pmac, 0, crand, &csum); assert(error == 0); toku_pma_verify_fingerprint(pmab, brand, bsum); toku_pma_verify_fingerprint(pmac, crand, csum); printf("a:"); toku_print_pma(pmaa); na = toku_pma_n_entries(pmaa); assert(na == 0); printf("b:"); toku_print_pma(pmab); nb = toku_pma_n_entries(pmab); printf("c:"); toku_print_pma(pmac); nc = toku_pma_n_entries(pmac); assert(nb + nc == 16); /* cursors open, should fail */ error = toku_pma_free(&pmab); assert(error != 0); /* walk cursora */ assert_cursor_val(cursora, 1); walk_cursor("cursora", cursora); /* walk cursorb */ assert_cursor_val(cursorb, 2); walk_cursor("cursorb", cursorb); /* walk cursorc */ assert_cursor_val(cursorc, 16); walk_cursor("cursorc", cursorc); walk_cursor_reverse("cursorc reverse", cursorc); error = toku_pma_cursor_free(&cursora); assert(error == 0); error = toku_pma_cursor_free(&cursorb); assert(error == 0); error = toku_pma_cursor_free(&cursorc); assert(error == 0); error = toku_pma_free(&pmaa); assert(error == 0); error = toku_pma_free(&pmab); assert(error == 0); error = toku_pma_free(&pmac); assert(error == 0); } static void test_pma_split(void) { test_pma_split_n(0); local_memory_check_all_free(); test_pma_split_n(1); local_memory_check_all_free(); test_pma_split_n(2); local_memory_check_all_free(); test_pma_split_n(4); local_memory_check_all_free(); test_pma_split_n(8); local_memory_check_all_free(); test_pma_split_n(9); local_memory_check_all_free(); test_pma_dup_split_n(0, TOKU_DB_DUP); local_memory_check_all_free(); test_pma_dup_split_n(1, TOKU_DB_DUP); local_memory_check_all_free(); test_pma_dup_split_n(9, TOKU_DB_DUP); local_memory_check_all_free(); test_pma_split_varkey(); local_memory_check_all_free(); test_pma_split_cursor(); local_memory_check_all_free(); } /* * test the toku_pma_bulk_insert function by creating n kv pairs and bulk * inserting them into an empty pma. verify that the pma contains all * of the kv pairs. */ static void test_pma_bulk_insert_n(int n) { PMA pma; int error; int i; DBT *keys, *vals; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; printf("test_pma_bulk_insert_n: %d\n", n); error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); /* init n kv pairs */ keys = toku_malloc(n * sizeof (DBT)); assert(keys); vals = toku_malloc(n * sizeof (DBT)); assert(vals); /* init n kv pairs */ for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = toku_pma_free(&pma); assert(r == 0); } /* * test that the pma shrinks to its minimum size after inserting * random keys and then deleting them. */ static void test_pma_delete_random(int n) { PMA pma; int r; int i; int keys[n]; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; printf("test_pma_delete_random:%d\n", n); r = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, n * (8 + 11 + sizeof (int))); assert(r == 0); for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = toku_pma_free(&pma); assert(r == 0); } static void assert_cursor_equal(PMA_CURSOR pmacursor, int v) { DBT key, val; toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; int r; r = toku_pma_cursor_get_current(pmacursor, &key, &val, 0); assert(r == 0); if (0) printf("key %s\n", (char*) key.data); int thev; assert(val.size == sizeof thev); memcpy(&thev, val.data, val.size); assert(thev == v); toku_free(key.data); toku_free(val.data); } static void assert_cursor_nokey(PMA_CURSOR pmacursor) { DBT key, val; toku_init_dbt(&key); key.flags = DB_DBT_MALLOC; toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; int r; r = toku_pma_cursor_get_current(pmacursor, &key, &val, 0); assert(r != 0); } /* * test that pma delete ops update pma cursors * - insert n keys * - point the cursor at the last key in the pma * - delete keys sequentially. the cursor should be stuck at the * last key until the last key is deleted. */ static void test_pma_delete_cursor(int n) { printf("test_delete_cursor:%d\n", n); PMA pma; int r; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; r = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(r == 0); int i; for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = toku_pma_cursor_free(&pmacursor); assert(r == 0); r = toku_pma_free(&pma); assert(r == 0); } /* * insert k,1 * place cursor at k * delete k * cursor get current * lookup k * insert k,2 * lookup k * cursor get current */ static void test_pma_delete_insert() { printf("test_pma_delete_insert\n"); PMA pma; int error; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); PMA_CURSOR pmacursor; error = toku_pma_cursor(pma, &pmacursor, &skey, &sval); assert(error == 0); DBT key, val; int k, v; k = 1; v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); error = toku_pma_cursor_set_position_first(pmacursor); assert(error == 0); assert_cursor_equal(pmacursor, 1); k = 1; v = 1; do_delete(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); assert_cursor_nokey(pmacursor); k = 1; toku_fill_dbt(&key, &k, sizeof k); toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_lookup(pma, &key, &val); assert(error != 0); k = 1; v = 2; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); assert_cursor_equal(pmacursor, 2); error = toku_pma_cursor_free(&pmacursor); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_double_delete() { printf("test_pma_double_delete\n"); PMA pma; int error; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); PMA_CURSOR pmacursor; error = toku_pma_cursor(pma, &pmacursor, &skey, &sval); assert(error == 0); DBT key; int k, v; k = 1; v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); error = toku_pma_cursor_set_position_first(pmacursor); assert(error == 0); assert_cursor_equal(pmacursor, 1); k = 1; v = 1; do_delete(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); assert_cursor_nokey(pmacursor); k = 1; toku_fill_dbt(&key, &k, sizeof k); error = toku_pma_delete(pma, &key, rand4fingerprint, &sum, 0); assert(error == DB_NOTFOUND); assert(sum == expect_fingerprint); error = toku_pma_cursor_free(&pmacursor); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_first_delete_last() { printf("test_pma_cursor_first_delete_last\n"); int error; PMA pma; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); int k, v; int i; for (i=1; i<=2; i++) { k = htonl(i); v = i; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } assert(toku_pma_n_entries(pma) == 2); PMA_CURSOR pmacursor; error = toku_pma_cursor(pma, &pmacursor, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_first(pmacursor); assert(error == 0); k = htonl(1); v = 1; do_delete(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); assert(toku_pma_n_entries(pma) == 2); error = toku_pma_cursor_set_position_last(pmacursor); assert(error == 0); assert(toku_pma_n_entries(pma) == 1); error = toku_pma_cursor_free(&pmacursor); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_last_delete_first() { printf("test_pma_cursor_last_delete_first\n"); int error; PMA pma; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); int k, v; int i; for (i=1; i<=2; i++) { k = htonl(i); v = i; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); } assert(toku_pma_n_entries(pma) == 2); PMA_CURSOR pmacursor; error = toku_pma_cursor(pma, &pmacursor, &skey, &sval); assert(error == 0); error = toku_pma_cursor_set_position_last(pmacursor); assert(error == 0); k = htonl(2); v = 2; do_delete(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); assert(toku_pma_n_entries(pma) == 2); error = toku_pma_cursor_set_position_first(pmacursor); assert(error == 0); assert(toku_pma_n_entries(pma) == 1); error = toku_pma_cursor_free(&pmacursor); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_delete() { test_pma_delete_shrink(256); local_memory_check_all_free(); test_pma_delete_random(256); local_memory_check_all_free(); test_pma_delete_cursor(32); local_memory_check_all_free(); test_pma_delete_insert(); local_memory_check_all_free(); test_pma_double_delete(); local_memory_check_all_free(); test_pma_cursor_first_delete_last(); local_memory_check_all_free(); test_pma_cursor_last_delete_first(); local_memory_check_all_free(); } static void test_pma_already_there() { printf("test_pma_already_there\n"); int error; PMA pma; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); DBT key, val; int k, v; k = 1; v = 1; toku_fill_dbt(&key, &k, sizeof k); toku_fill_dbt(&val, &v, sizeof v); error = toku_pma_insert(pma, &key, &val, NULL_ARGS, rand4fingerprint, &sum); assert(error == 0); u_int32_t savesum = sum; error = toku_pma_insert(pma, &key, &val, NULL_ARGS, rand4fingerprint, &sum); assert(error == BRT_ALREADY_THERE); assert(sum==savesum); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_set_key() { printf("test_pma_cursor_set_key\n"); int error; PMA pma; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, 0); assert(error == 0); DBT key, val; int k, v; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; const int n = 100; int i; for (i=0; i largest_key); } else { toku_init_dbt(&val); val.flags = DB_DBT_MALLOC; error = toku_pma_cursor_get_current(cursor, &key, &val, 0); assert(error == 0); int vv; assert(val.size == sizeof vv); memcpy(&vv, val.data, val.size); if (i <= smallest_key) assert(vv == smallest_key); else assert(vv == (((i+9)/10)*10)); toku_free(val.data); } } error = toku_pma_cursor_free(&cursor); assert(error == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_delete_under() { printf("test_pma_cursor_delete_under\n"); int error; PMA pma; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; const int n = 1000; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, n * (8 + sizeof (int) + sizeof (int))); assert(error == 0); PMA_CURSOR cursor; error = toku_pma_cursor(pma, &cursor, &skey, &sval); assert(error == 0); int kvsize, lastkey; /* delete under an uninitialized cursor should fail */ error = toku_pma_cursor_delete_under(cursor, &kvsize, rand4fingerprint, &expect_fingerprint, 0); assert(error == DB_NOTFOUND); int k, v; /* insert 0 .. n-1 */ int i; for (i=0; i= n-2) assert(lastkey); /* 2nd delete under should fail */ error = toku_pma_cursor_delete_under(cursor, &kvsize, rand4fingerprint, &expect_fingerprint, &lastkey); assert(error == DB_NOTFOUND); } assert(i == n); error = toku_pma_cursor_free(&cursor); assert(error == 0); assert(toku_pma_n_entries(pma) == 0); error = toku_pma_free(&pma); assert(error == 0); } static void test_pma_cursor_set_both() { printf("test_pma_cursor_set_both\n"); int error; PMA pma; u_int32_t rand4fingerprint = random(); u_int32_t sum = 0; u_int32_t expect_fingerprint = 0; const int n = 1000; error = toku_pma_create(&pma, toku_default_compare_fun, null_db, null_filenum, n * (8 + sizeof (int) + sizeof (int))); assert(error == 0); PMA_CURSOR cursor; error = toku_pma_cursor(pma, &cursor, &skey, &sval); assert(error == 0); DBT key, val; int k, v; int i; /* insert 0->0, 1->1, .. n-1->n-1 */ for (i=0; i0, 0->1, .. 0->n-1 */ DBT key, val; int k, v; int i; for (i=0; i1, 3->3 */ k = htonl(1); v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); k = htonl(3); v = 3; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); int i; /* insert 2->0, 2->1, .. 2->n-1 */ for (i=0; i1, 3->3 */ k = htonl(1); v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); k = htonl(3); v = 3; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); u_int32_t sum_before_all_the_duplicates = sum; int i; /* insert 2->0, 2->1, .. 2->n-1 */ for (i=0; i1, 3->3 */ k = htonl(1); v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); k = htonl(3); v = 3; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); k = htonl(2); int values[n]; int i; for (i=0; in-i */ for (i=0; i1, 3->3 */ k = htonl(1); v = 1; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); k = htonl(3); v = 3; do_insert(pma, &k, sizeof k, &v, sizeof v, rand4fingerprint, &sum, &expect_fingerprint); toku_pma_verify(pma); int i; /* insert 2->0, 2->1, .. 2->n-1 */ for (i=0; i