#include "../include/ydb-constants.h" #include "memory.h" #include "key.h" #include #include #include #include #include #include "list.h" #include "kv-pair.h" #include "pma-internal.h" static void test_make_space_at (void) { PMA pma; char *key; int r; 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=pma_create(&pma, default_compare_fun); assert(r==0); assert(pma_n_entries(pma)==0); r=pmainternal_make_space_at(pma, 2); assert(pma_index_limit(pma)==4); assert((unsigned long)pma->pairs[pma_index_limit(pma)]==0xdeadbeefL); print_pma(pma); pma->pairs[2] = key_A; pma->n_pairs_present++; r=pmainternal_make_space_at(pma,2); printf("Requested space at 2, got space at %d\n", r); print_pma(pma); assert(pma->pairs[r]==0); assert((unsigned long)pma->pairs[pma_index_limit(pma)]==0xdeadbeefL); assert(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; print_pma(pma); r=pmainternal_make_space_at(pma,0); printf("Requested space at 0, got space at %d\n", r); print_pma(pma); assert((unsigned long)pma->pairs[pma_index_limit(pma)]==0xdeadbeefL); // make sure it doesn't go off the end. assert(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; print_pma(pma); r=pmainternal_make_space_at(pma,5); print_pma(pma); printf("r=%d\n", r); { int i; for (i=0; ipairs[i]) { assert(ipairs[i] = 0; } } } pma->n_pairs_present = 0; r=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; int i; int r; const 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(pma_index_limit(pma)==N); pma->compare_fun = default_compare_fun; r=pmainternal_find(pma, fill_dbt(&k, "hello", 5), 0); assert(r==0); pma->pairs[5] = kv_pair_malloc("hello", 5, 0, 0); assert(pma_index_limit(pma)==N); r=pmainternal_find(pma, fill_dbt(&k, "hello", 5), 0); assert(pma_index_limit(pma)==N); assert(r==5); r=pmainternal_find(pma, fill_dbt(&k, "there", 5), 0); assert(r==6); r=pmainternal_find(pma, fill_dbt(&k, "aaa", 3), 0); assert(r==0); pma->pairs[N-1] = kv_pair_malloc("there", 5, 0, 0); r=pmainternal_find(pma, fill_dbt(&k, "hello", 5), 0); assert(r==5); r=pmainternal_find(pma, fill_dbt(&k, "there", 5), 0); assert(r==N-1); r=pmainternal_find(pma, fill_dbt(&k, "aaa", 3), 0); assert(r==0); r=pmainternal_find(pma, fill_dbt(&k, "hellob", 6), 0); assert(r==6); r=pmainternal_find(pma, fill_dbt(&k, "zzz", 3), 0); assert(r==N); for (i=0; ipairs[i]) kv_pair_free(pma->pairs[i]); toku_free(pma->pairs); toku_free(pma); } 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; pmainternal_calculate_parameters(&pma); assert(pma.uplgN==2); assert(pma.udt_step==0.5); pma.N=8; 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[pma_index_limit(pma)]==0xdeadbeefL); r=pma_insert(pma, fill_dbt(&k, "00000", 6), fill_dbt(&v, "d0", 3), 0); assert(r==BRT_OK); assert((unsigned long)pma->pairs[pma_index_limit(pma)]==0xdeadbeefL); r=pma_free(&pma); assert(r==0); assert(pma==0); pma_create(&pma, default_compare_fun); assert(pma!=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\n", i, string, dstring); r=pma_insert(pma, fill_dbt(&k, string, strlen(string)+1), fill_dbt(&v, dstring, strlen(dstring)+1), 0); assert(r==BRT_OK); } } r=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; 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; DBT k,v; pma_create(&pma, default_compare_fun); r=pma_insert(pma, fill_dbt(&k, "42", 3), fill_dbt(&v, "-19", 4), 0); assert(r==BRT_OK); test_pma_iterate_internal(pma, 42, -19); r=pma_insert(pma, fill_dbt(&k, "12", 3), fill_dbt(&v, "-100", 5), 0); assert(r==BRT_OK); test_pma_iterate_internal(pma, 42+12, -19-100); r=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; DBT k,v; r=pma_create(&pma0, default_compare_fun); assert(r==0); r=pma_create(&pma1, default_compare_fun); assert(r==0); pma_insert(pma0, fill_dbt(&k, "a", 2), fill_dbt(&v, "aval", 5), 0); pma_insert(pma0, fill_dbt(&k, "b", 2), fill_dbt(&v, "bval", 5), 0); pma_insert(pma1, fill_dbt(&k, "x", 2), fill_dbt(&v, "xval", 5), 0); 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=pma_free(&pma0); assert(r==0); assert(pma0==0); r=pma_free(&pma1); assert(r==0); assert(pma1==0); } /* Check to see if we can create and kill a cursor. */ void test_pma_cursor_0 (void) { PMA pma; PMA_CURSOR c=0; int r; r=pma_create(&pma, default_compare_fun); assert(r==0); r=pma_cursor(pma, &c); assert(r==0); assert(c!=0); printf("%s:%d\n", __FILE__, __LINE__); r=pma_free(&pma); assert(r!=0); /* didn't deallocate the cursor. */ printf("%s:%d\n", __FILE__, __LINE__); r=pma_cursor_free(&c); assert(r==0); printf("%s:%d\n", __FILE__, __LINE__); r=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. */ 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=pma_create(&pma, default_compare_fun); assert(r==0); r=pma_cursor(pma, &c0); assert(r==0); assert(c0!=0); r=pma_cursor(pma, &c1); assert(r==0); assert(c1!=0); r=pma_cursor(pma, &c2); assert(r==0); assert(c2!=0); r=pma_free(&pma); assert(r!=0); if (order<2) { r=pma_cursor_free(&c0); assert(r==0); c0=c1; c1=c2; } else if (order<4) { r=pma_cursor_free(&c1); assert(r==0); c1=c2; } else { r=pma_cursor_free(&c2); assert(r==0); } r=pma_free(&pma); assert(r!=0); if (order%2==0) { r=pma_cursor_free(&c0); assert(r==0); c0=c1; } else { r=pma_cursor_free(&c1); assert(r==0); } r=pma_free(&pma); assert(r!=0); r = pma_cursor_free(&c0); assert(r==0); r=pma_free(&pma); assert(r==0); } } void test_pma_cursor_2 (void) { PMA pma; PMA_CURSOR c=0; int r; DBT key,val; init_dbt(&key); key.flags=DB_DBT_REALLOC; init_dbt(&val); val.flags=DB_DBT_REALLOC; r=pma_create(&pma, default_compare_fun); assert(r==0); r=pma_cursor(pma, &c); assert(r==0); assert(c!=0); r=pma_cursor_set_position_last(c); assert(r==DB_NOTFOUND); r=pma_cursor_free(&c); assert(r==0); r=pma_free(&pma); assert(r==0); } void test_pma_cursor_3 (void) { PMA pma; PMA_CURSOR c=0; int r; DBT key,val; DBT k,v; r=pma_create(&pma, default_compare_fun); assert(r==0); r=pma_insert(pma, fill_dbt(&k, "x", 2), fill_dbt(&v, "xx", 3), 0); assert(r==BRT_OK); r=pma_insert(pma, fill_dbt(&k, "m", 2), fill_dbt(&v, "mm", 3), 0); assert(r==BRT_OK); r=pma_insert(pma, fill_dbt(&k, "aa", 3), fill_dbt(&v,"a", 2), 0); assert(r==BRT_OK); init_dbt(&key); key.flags=DB_DBT_REALLOC; init_dbt(&val); val.flags=DB_DBT_REALLOC; r=pma_cursor(pma, &c); assert(r==0); assert(c!=0); r=pma_cursor_set_position_first(c); assert(r==0); r=pma_cget_current(c, &key, &val); 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=pma_cursor_set_position_next(c); assert(r==0); r=pma_cget_current(c, &key, &val); 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=pma_cursor_set_position_next(c); assert(r==0); r=pma_cget_current(c, &key, &val); 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=pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); /* After an error, the cursor should still point at the same thing. */ r=pma_cget_current(c, &key, &val); 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=pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); toku_free(key.data); toku_free(val.data); r=pma_cursor_free(&c); assert(r==0); r=pma_free(&pma); assert(r==0); } void assert_cursor_val(PMA_CURSOR cursor, int v) { DBT key, val; int error; init_dbt(&key); key.flags = DB_DBT_MALLOC; init_dbt(&val); val.flags = DB_DBT_MALLOC; error = pma_cget_current(cursor, &key, &val); 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 */ void test_pma_cursor_4 (void) { int error; PMA pma; PMA_CURSOR cursora, cursorb, cursorc; int i; printf("test_pma_cursor_4\n"); error = pma_create(&pma, default_compare_fun); assert(error == 0); for (i=1; i<=4; i += 1) { DBT dbtk, dbtv; char k[5]; int v; sprintf(k, "%4.4d", i); fill_dbt(&dbtk, &k, strlen(k)+1); v = i; fill_dbt(&dbtv, &v, sizeof v); error = pma_insert(pma, &dbtk, &dbtv, 0); assert(error == BRT_OK); } assert(pma_n_entries(pma) == 4); printf("a:"); print_pma(pma); error = pma_cursor(pma, &cursora); assert(error == 0); error = pma_cursor_set_position_first(cursora); assert(error == 0); assert_cursor_val(cursora, 1); error = pma_cursor(pma, &cursorb); assert(error == 0); error = pma_cursor_set_position_first(cursorb); assert(error == 0); assert_cursor_val(cursorb, 1); error = pma_cursor_set_position_next(cursorb); assert(error == 0); assert_cursor_val(cursorb, 2); error = pma_cursor(pma, &cursorc); assert(error == 0); error = pma_cursor_set_position_last(cursorc); assert(error == 0); assert_cursor_val(cursorc, 4); for (i=5; i<=8; i += 1) { DBT dbtk, dbtv; char k[5]; int v; sprintf(k, "%4.4d", i); fill_dbt(&dbtk, &k, strlen(k)+1); v = i; fill_dbt(&dbtv, &v, sizeof v); error = pma_insert(pma, &dbtk, &dbtv, 0); assert(error == BRT_OK); } assert(pma_n_entries(pma) == 8); printf("a:"); print_pma(pma); assert_cursor_val(cursora, 1); assert_cursor_val(cursorb, 2); assert_cursor_val(cursorc, 4); error = pma_cursor_free(&cursora); assert(error == 0); error = pma_cursor_free(&cursorb); assert(error == 0); error = pma_cursor_free(&cursorc); assert(error == 0); error = pma_free(&pma); assert(error == 0); } void test_pma_cursor_delete(int n) { printf("test_pma_cursor_delete:%d\n", n); PMA pma; int error; error = pma_create(&pma, default_compare_fun); assert(error == 0); /* insert 1 -> 42 */ DBT key, val; 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; } 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; DBT k,v; r = pma_create(&pma, wrong_endian_p ? wrong_endian_compare_fun : default_compare_fun); assert(r==0); r = pma_insert(pma, fill_dbt(&k, "10", 3), fill_dbt(&v, "10v", 4), 0); assert(r==BRT_OK); r = pma_insert(pma, fill_dbt(&k, "00", 3), fill_dbt(&v, "00v", 4), 0); assert(r==BRT_OK); r = pma_insert(pma, fill_dbt(&k, "01", 3), fill_dbt(&v, "01v", 4), 0); assert(r==BRT_OK); r = pma_insert(pma, fill_dbt(&k, "11", 3), fill_dbt(&v, "11v", 4), 0); assert(r==BRT_OK); init_dbt(&key); key.flags=DB_DBT_REALLOC; init_dbt(&val); val.flags=DB_DBT_REALLOC; r=pma_cursor(pma, &c); assert(r==0); assert(c!=0); for (i=0; i<4; i++) { if (i==0) { r=pma_cursor_set_position_first(c); assert(r==0); } else { r=pma_cursor_set_position_next(c); assert(r==0); } r=pma_cget_current(c, &key, &val); 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=pma_cursor_set_position_next(c); assert(r==DB_NOTFOUND); toku_free(key.data); toku_free(val.data); r=pma_cursor_free(&c); assert(r==0); r=pma_free(&pma); assert(r==0); } void test_pma_split_n(int n) { PMA pmaa, pmab, pmac; int error; int i; int na, nb, nc; printf("test_pma_split_n:%d\n", n); error = pma_create(&pmaa, default_compare_fun); assert(error == 0); error = pma_create(&pmab, default_compare_fun); assert(error == 0); error = pma_create(&pmac, default_compare_fun); assert(error == 0); /* insert some kv pairs */ for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = pma_free(&pma); assert(r == 0); } /* * test that the pma shrinks to its minimum size after inserting * random keys and then deleting them. */ void test_pma_delete_random(int n) { PMA pma; int r; int i; int keys[n]; printf("test_pma_delete_random:%d\n", n); r = pma_create(&pma, default_compare_fun); assert(r == 0); for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = pma_free(&pma); assert(r == 0); } void assert_cursor_equal(PMA_CURSOR pmacursor, int v) { DBT key, val; init_dbt(&key); key.flags = DB_DBT_MALLOC; init_dbt(&val); val.flags = DB_DBT_MALLOC; int r; r = pma_cget_current(pmacursor, &key, &val); 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); } void assert_cursor_nokey(PMA_CURSOR pmacursor) { DBT key, val; init_dbt(&key); key.flags = DB_DBT_MALLOC; init_dbt(&val); val.flags = DB_DBT_MALLOC; int r; r = pma_cget_current(pmacursor, &key, &val); 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. */ void test_pma_delete_cursor(int n) { printf("test_delete_cursor:%d\n", n); PMA pma; int r; r = pma_create(&pma, default_compare_fun); assert(r == 0); int i; for (i=0; iN == PMA_MIN_ARRAY_SIZE); r = pma_cursor_free(&pmacursor); assert(r == 0); r = 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 */ void test_pma_delete_insert() { printf("test_pma_delete_insert\n"); PMA pma; int error; error = pma_create(&pma, default_compare_fun); assert(error == 0); PMA_CURSOR pmacursor; error = pma_cursor(pma, &pmacursor); assert(error == 0); DBT key, val; int k, v; k = 1; v = 1; fill_dbt(&key, &k, sizeof k); fill_dbt(&val, &v, sizeof v); error = pma_insert(pma, &key, &val, 0); assert(error == 0); error = pma_cursor_set_position_first(pmacursor); assert(error == 0); assert_cursor_equal(pmacursor, 1); k = 1; fill_dbt(&key, &k, sizeof k); error = pma_delete(pma, &key, 0); assert(error == 0); assert_cursor_nokey(pmacursor); k = 1; fill_dbt(&key, &k, sizeof k); init_dbt(&val); val.flags = DB_DBT_MALLOC; error = pma_lookup(pma, &key, &val, 0); assert(error != 0); k = 1; v = 2; fill_dbt(&key, &k, sizeof k); fill_dbt(&val, &v, sizeof v); error = pma_insert(pma, &key, &val, 0); assert(error == 0); assert_cursor_equal(pmacursor, 2); error = pma_cursor_free(&pmacursor); assert(error == 0); error = pma_free(&pma); assert(error == 0); } void test_pma_delete() { test_pma_delete_shrink(256); memory_check_all_free(); test_pma_delete_random(256); memory_check_all_free(); test_pma_delete_cursor(32); memory_check_all_free(); test_pma_delete_insert(); memory_check_all_free(); } void pma_tests (void) { memory_check=1; test_keycompare(); memory_check_all_free(); test_pma_compare_fun(0); memory_check_all_free(); test_pma_compare_fun(1); memory_check_all_free(); test_pma_iterate(); test_pma_iterate2(); memory_check_all_free(); test_make_space_at(); memory_check_all_free(); test_smooth_region(); memory_check_all_free(); test_find_insert(); memory_check_all_free(); test_pma_find(); memory_check_all_free(); test_calculate_parameters(); memory_check_all_free(); test_count_region(); memory_check_all_free(); test_pma_random_pick(); memory_check_all_free(); test_pma_cursor(); memory_check_all_free(); test_pma_split(); memory_check_all_free(); test_pma_bulk_insert(); memory_check_all_free(); test_pma_insert_or_replace(); memory_check_all_free(); test_pma_delete(); } int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) { pma_tests(); malloc_cleanup(); return 0; }