/* -*- 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 . ---------------------------------------- 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 . ======= */ #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." #include "test.h" static TOKUTXN const null_txn = 0; static const char *fname = TOKU_TEST_FILENAME; static void test_dump_empty_db (void) { FT_HANDLE t; CACHETABLE ct; int r; toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); unlink(fname); r = toku_open_ft_handle(fname, 1, &t, 1024, 256, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); if (verbose) { r=toku_dump_ft(stdout, t); assert(r==0); } r = toku_close_ft_handle_nolsn(t, 0); assert(r==0); toku_cachetable_close(&ct); } /* Test running multiple trees in different files */ static void test_multiple_files_of_size (int size) { char n0[TOKU_PATH_MAX+1]; toku_path_join(n0, 2, TOKU_TEST_FILENAME, "test0.dat"); char n1[TOKU_PATH_MAX+1]; toku_path_join(n1, 2, TOKU_TEST_FILENAME, "test1.dat"); CACHETABLE ct; FT_HANDLE t0,t1; int r,i; if (verbose) printf("test_multiple_files_of_size(%d)\n", size); toku_os_recursive_delete(TOKU_TEST_FILENAME); r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU); assert(r == 0); toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); r = toku_open_ft_handle(n0, 1, &t0, size, size / 4, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); r = toku_open_ft_handle(n1, 1, &t1, size, size / 4, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); for (i=0; i<10000; i++) { char key[100],val[100]; DBT k,v; snprintf(key, 100, "key%d", i); snprintf(val, 100, "val%d", i); toku_ft_insert(t0, toku_fill_dbt(&k, key, 1+strlen(key)), toku_fill_dbt(&v, val, 1+strlen(val)), null_txn); snprintf(val, 100, "Val%d", i); toku_ft_insert(t1, toku_fill_dbt(&k, key, 1+strlen(key)), toku_fill_dbt(&v, val, 1+strlen(val)), null_txn); } //toku_verify_ft(t0); //dump_ft(t0); //dump_ft(t1); r = toku_verify_ft(t0); assert(r==0); r = toku_verify_ft(t1); assert(r==0); r = toku_close_ft_handle_nolsn(t0, 0); assert(r==0); r = toku_close_ft_handle_nolsn(t1, 0); assert(r==0); toku_cachetable_close(&ct); /* Now see if the data is all there. */ toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); r = toku_open_ft_handle(n0, 0, &t0, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); if (verbose) printf("%s:%d r=%d\n", __FILE__, __LINE__,r); assert(r==0); r = toku_open_ft_handle(n1, 0, &t1, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); for (i=0; i<10000; i++) { char key[100],val[100]; snprintf(key, 100, "key%d", i); snprintf(val, 100, "val%d", i); ft_lookup_and_check_nodup(t0, key, val); snprintf(val, 100, "Val%d", i); ft_lookup_and_check_nodup(t1, key, val); } r = toku_close_ft_handle_nolsn(t0, 0); assert(r==0); r = toku_close_ft_handle_nolsn(t1, 0); assert(r==0); toku_cachetable_close(&ct); toku_os_recursive_delete(TOKU_TEST_FILENAME); } static void test_multiple_files (void) { test_multiple_files_of_size (1<<12); test_multiple_files_of_size (1<<20); } /* Test to see that a single db can be opened many times. */ static void test_multiple_ft_handles_one_db_one_file (void) { enum { MANYN = 2 }; int i, r; CACHETABLE ct; FT_HANDLE trees[MANYN]; if (verbose) printf("test_multiple_ft_handles_one_db_one_file:"); unlink(fname); toku_cachetable_create(&ct, 32, ZERO_LSN, nullptr); for (i=0; idata); unsigned char *CAST_FROM_VOIDP(bd, b->data); unsigned int siz=a->size; assert(a->size==b->size); //assert(db==&nonce_db); // make sure the db was passed down correctly for (i=0; ibd[siz-1-i]) return +1; } return 0; } static void test_wrongendian_compare (int wrong_p, unsigned int N) { CACHETABLE ct; FT_HANDLE ft; int r; unsigned int i; unlink(fname); { char a[4]={0,1,0,0}; char b[4]={1,0,0,0}; DBT at, bt; assert(wrong_compare_fun(NULL, toku_fill_dbt(&at, a, 4), toku_fill_dbt(&bt, b, 4))>0); assert(wrong_compare_fun(NULL, toku_fill_dbt(&at, b, 4), toku_fill_dbt(&bt, a, 4))<0); } toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); //printf("%s:%d WRONG=%d\n", __FILE__, __LINE__, wrong_p); if (0) { // ???? Why is this commented out? r = toku_open_ft_handle(fname, 1, &ft, 1<<20, 1<<17, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, wrong_p ? wrong_compare_fun : toku_builtin_compare_fun); assert(r==0); for (i=1; i<257; i+=255) { unsigned char a[4],b[4]; b[3] = a[0] = (unsigned char)(i&255); b[2] = a[1] = (unsigned char)((i>>8)&255); b[1] = a[2] = (unsigned char)((i>>16)&255); b[0] = a[3] = (unsigned char)((i>>24)&255); DBT kbt; toku_fill_dbt(&kbt, a, sizeof a); DBT vbt; toku_fill_dbt(&vbt, b, sizeof b); if (verbose) printf("%s:%d insert: %02x%02x%02x%02x -> %02x%02x%02x%02x\n", __FILE__, __LINE__, ((char*)kbt.data)[0], ((char*)kbt.data)[1], ((char*)kbt.data)[2], ((char*)kbt.data)[3], ((char*)vbt.data)[0], ((char*)vbt.data)[1], ((char*)vbt.data)[2], ((char*)vbt.data)[3]); toku_ft_insert(ft, &kbt, &vbt, null_txn); } { FT_CURSOR cursor=0; r = toku_ft_cursor(ft, &cursor, NULL, false, false); assert(r==0); for (i=0; i<2; i++) { unsigned char a[4],b[4]; struct check_pair pair = {4, &a, 4, &b, 0}; b[3] = a[0] = (unsigned char)(i&255); b[2] = a[1] = (unsigned char)((i>>8)&255); b[1] = a[2] = (unsigned char)((i>>16)&255); b[0] = a[3] = (unsigned char)((i>>24)&255); r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT); assert(r==0); assert(pair.call_count==1); } r = toku_close_ft_handle_nolsn(ft, 0); } } { toku_cachetable_verify(ct); r = toku_open_ft_handle(fname, 1, &ft, 1<<20, 1<<17, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, wrong_p ? wrong_compare_fun : toku_builtin_compare_fun); assert(r==0); toku_cachetable_verify(ct); for (i=0; i>8)&255); b[1] = a[2] = (unsigned char)((i>>16)&255); b[0] = a[3] = (unsigned char)((i>>24)&255); DBT kbt; toku_fill_dbt(&kbt, a, sizeof a); DBT vbt; toku_fill_dbt(&vbt, b, sizeof b); if (0) printf("%s:%d insert: %02x%02x%02x%02x -> %02x%02x%02x%02x\n", __FILE__, __LINE__, ((unsigned char*)kbt.data)[0], ((unsigned char*)kbt.data)[1], ((unsigned char*)kbt.data)[2], ((unsigned char*)kbt.data)[3], ((unsigned char*)vbt.data)[0], ((unsigned char*)vbt.data)[1], ((unsigned char*)vbt.data)[2], ((unsigned char*)vbt.data)[3]); toku_ft_insert(ft, &kbt, &vbt, null_txn); toku_cachetable_verify(ct); } FT_CURSOR cursor=0; r = toku_ft_cursor(ft, &cursor, NULL, false, false); assert(r==0); for (i=0; i>8)&255); b[1] = a[2] = (unsigned char)((i>>16)&255); b[0] = a[3] = (unsigned char)((i>>24)&255); r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT); assert(r==0); assert(pair.call_count==1); toku_cachetable_verify(ct); } toku_ft_cursor_close(cursor); r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0); } toku_cachetable_close(&ct); } static int test_ft_cursor_keycompare(DB *desc __attribute__((unused)), const DBT *a, const DBT *b) { return toku_keycompare(a->data, a->size, b->data, b->size); } static void test_large_kv(int bsize, int ksize, int vsize) { FT_HANDLE t; int r; CACHETABLE ct; if (verbose) printf("test_large_kv: %d %d %d\n", bsize, ksize, vsize); toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); unlink(fname); r = toku_open_ft_handle(fname, 1, &t, bsize, bsize / 4, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); DBT key, val; char *k, *v; XCALLOC_N(ksize, k); XCALLOC_N(vsize, v); toku_fill_dbt(&key, k, ksize); toku_fill_dbt(&val, v, vsize); toku_ft_insert(t, &key, &val, 0); toku_free(k); toku_free(v); r = toku_close_ft_handle_nolsn(t, 0); assert(r==0); toku_cachetable_close(&ct); } /* * test the key and value limits * the current implementation crashes when kvsize == bsize/2 rather than fails */ static void test_ft_limits(void) { int bsize = 1024; int kvsize = 4; while (kvsize < bsize/2) { test_large_kv(bsize, kvsize, kvsize); kvsize *= 2; } } /* * verify that a delete on an empty tree fails */ static void test_ft_delete_empty(void) { if (verbose) printf("test_ft_delete_empty\n"); FT_HANDLE t; int r; CACHETABLE ct; toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); unlink(fname); r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); DBT key; int k = toku_htonl(1); toku_fill_dbt(&key, &k, sizeof k); toku_ft_delete(t, &key, null_txn); r = toku_close_ft_handle_nolsn(t, 0); assert(r==0); toku_cachetable_close(&ct); } /* * insert n keys, delete all n keys, verify that lookups for all the keys fail, * verify that a cursor walk of the tree finds nothing */ static void test_ft_delete_present(int n) { if (verbose) printf("test_ft_delete_present:%d\n", n); FT_HANDLE t; int r; CACHETABLE ct; int i; toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); unlink(fname); r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0); /* insert 0 .. n-1 */ for (i=0; i 0) { { int k = toku_htonl(n-1); DBT key; toku_fill_dbt(&key, &k, sizeof k); toku_ft_delete(t, &key, null_txn); } { int k = toku_htonl(n-1); DBT key; toku_fill_dbt(&key, &k, sizeof k); struct check_pair pair = {0,0,0,0,0}; r = toku_ft_lookup(t, &key, lookup_checkf, &pair); assert(r == DB_NOTFOUND); assert(pair.call_count==0); } } r = toku_close_ft_handle_nolsn(t, 0); assert(r==0); toku_cachetable_close(&ct); } /* insert <0,0>, <0,1>, .. <0,n> delete_both <0,i> for all even i verify <0,i> exists for all odd i */ static void test_ft_delete(void) { test_ft_delete_empty(); test_ft_delete_present(1); test_ft_delete_present(100); test_ft_delete_present(500); test_ft_delete_not_present(1); test_ft_delete_not_present(100); test_ft_delete_not_present(500); test_ft_delete_cursor_first(1); test_ft_delete_cursor_first(100); test_ft_delete_cursor_first(500); test_ft_delete_cursor_first(10000); test_insert_delete_lookup(2); test_insert_delete_lookup(512); } static void test_new_ft_cursor_create_close (void) { int r; FT_HANDLE ft=0; int n = 8; FT_CURSOR cursors[n]; toku_ft_handle_create(&ft); int i; for (i=0; i= v */ for (i=0; i max_key) { /* there is no smallest key if v > the max key */ assert(r == DB_NOTFOUND); assert(pair.call_count==0); } else { assert(r == 0); assert(pair.call_count==1); } } toku_ft_cursor_close(cursor); r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0); toku_cachetable_close(&ct); } static void test_new_ft_cursor_set(int n, int cursor_op, DB *db) { if (verbose) printf("test_ft_cursor_set:%d %d %p\n", n, cursor_op, db); int r; CACHETABLE ct; FT_HANDLE ft; FT_CURSOR cursor=0; unlink(fname); toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare); assert(r==0); int i; /* insert keys 0, 10, 20 .. 10*(n-1) */ for (i=0; i