1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
new(max_size: usize, capacity: usize) -> Encoder39 #include "test.h"
40 
41 static TOKUTXN const null_txn = 0;
42 
43 static const char *fname = TOKU_TEST_FILENAME;
44 
45 static void test_dump_empty_db (void) {
46     FT_HANDLE t;
47     CACHETABLE ct;
48     int r;
49 
update_max_size(&mut self, val: usize)50     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
51     unlink(fname);
52     r = toku_open_ft_handle(fname, 1, &t, 1024, 256, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
53     assert(r==0);
54     if (verbose) { r=toku_dump_ft(stdout, t); assert(r==0); }
55     r = toku_close_ft_handle_nolsn(t, 0);          assert(r==0);
56     toku_cachetable_close(&ct);
57 
58 }
59 
60 /* Test running multiple trees in different files */
61 static void test_multiple_files_of_size (int size) {
62     char n0[TOKU_PATH_MAX+1];
63     toku_path_join(n0, 2, TOKU_TEST_FILENAME, "test0.dat");
64     char n1[TOKU_PATH_MAX+1];
65     toku_path_join(n1, 2, TOKU_TEST_FILENAME, "test1.dat");
66     CACHETABLE ct;
67     FT_HANDLE t0,t1;
68     int r,i;
69     if (verbose) printf("test_multiple_files_of_size(%d)\n", size);
70     toku_os_recursive_delete(TOKU_TEST_FILENAME);
71     r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU); assert(r == 0);
72 
73     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
74     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);
75     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);
76     for (i=0; i<10000; i++) {
77 	char key[100],val[100];
78 	DBT k,v;
79 	snprintf(key, 100, "key%d", i);
80 	snprintf(val, 100, "val%d", i);
encode<I>( &mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut DstBuf<'_>, ) -> Encode where I: Iterator<Item = Header<Option<HeaderName>>>,81 	toku_ft_insert(t0, toku_fill_dbt(&k, key, 1+strlen(key)), toku_fill_dbt(&v, val, 1+strlen(val)), null_txn);
82 	snprintf(val, 100, "Val%d", i);
83 	toku_ft_insert(t1, toku_fill_dbt(&k, key, 1+strlen(key)), toku_fill_dbt(&v, val, 1+strlen(val)), null_txn);
84     }
85     //toku_verify_ft(t0);
86     //dump_ft(t0);
87     //dump_ft(t1);
88     r = toku_verify_ft(t0); assert(r==0);
89     r = toku_verify_ft(t1); assert(r==0);
90 
91     r = toku_close_ft_handle_nolsn(t0, 0); assert(r==0);
92     r = toku_close_ft_handle_nolsn(t1, 0); assert(r==0);
93     toku_cachetable_close(&ct);
94 
95 
96     /* Now see if the data is all there. */
97     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
98     r = toku_open_ft_handle(n0, 0, &t0, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
99     if (verbose) printf("%s:%d r=%d\n", __FILE__, __LINE__,r);
100     assert(r==0);
101     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);
102 
103     for (i=0; i<10000; i++) {
104 	char key[100],val[100];
105 	snprintf(key, 100, "key%d", i);
106 	snprintf(val, 100, "val%d", i);
107 	ft_lookup_and_check_nodup(t0, key, val);
108 	snprintf(val, 100, "Val%d", i);
109 	ft_lookup_and_check_nodup(t1, key, val);
110     }
111 
112     r = toku_close_ft_handle_nolsn(t0, 0); assert(r==0);
113     r = toku_close_ft_handle_nolsn(t1, 0); assert(r==0);
114     toku_cachetable_close(&ct);
115 
116     toku_os_recursive_delete(TOKU_TEST_FILENAME);
117 }
118 
119 static void test_multiple_files (void) {
120     test_multiple_files_of_size (1<<12);
121     test_multiple_files_of_size (1<<20);
122 }
123 
124 /* Test to see that a single db can be opened many times.  */
125 static void test_multiple_ft_handles_one_db_one_file (void) {
126     enum { MANYN = 2 };
127     int i, r;
128     CACHETABLE ct;
129     FT_HANDLE trees[MANYN];
130     if (verbose) printf("test_multiple_ft_handles_one_db_one_file:");
131 
132     unlink(fname);
133     toku_cachetable_create(&ct, 32, ZERO_LSN, nullptr);
134     for (i=0; i<MANYN; i++) {
135 	r = toku_open_ft_handle(fname, (i==0), &trees[i], 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
136 	assert(r==0);
137     }
138     for (i=0; i<MANYN; i++) {
139 	char k[20], v[20];
140 	DBT kb, vb;
141 	snprintf(k, 20, "key%d", i);
142 	snprintf(v, 20, "val%d", i);
143 	toku_ft_insert(trees[i], toku_fill_dbt(&kb, k, strlen(k)+1), toku_fill_dbt(&vb, v, strlen(v)+1), null_txn);
144     }
145     for (i=0; i<MANYN; i++) {
146 	char k[20],vexpect[20];
147 	snprintf(k, 20, "key%d", i);
148 	snprintf(vexpect, 20, "val%d", i);
149 	ft_lookup_and_check_nodup(trees[0], k, vexpect);
150     }
151     for (i=0; i<MANYN; i++) {
152 	r=toku_close_ft_handle_nolsn(trees[i], 0); assert(r==0);
153     }
154     toku_cachetable_close(&ct);
155 
156     if (verbose) printf(" ok\n");
157 }
158 
159 
160 /* Check to see if data can be read that was written. */
encode_size_updates(&mut self, dst: &mut DstBuf<'_>) -> Result<(), EncoderError>161 static void  test_read_what_was_written (void) {
162     CACHETABLE ct;
163     FT_HANDLE ft;
164     int r;
165     const int NVALS=10000;
166 
167     if (verbose) {
168         printf("test_read_what_was_written(): "); fflush(stdout);
169     }
170 
171     unlink(fname);
172 
173     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
174     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);  assert(r==0);
175     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
176     toku_cachetable_close(&ct);
177 
178     /* Now see if we can read an empty tree in. */
179     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
180     r = toku_open_ft_handle(fname, 0, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);  assert(r==0);
181 
182     /* See if we can put something in it. */
183     {
184 	DBT k,v;
185 	toku_ft_insert(ft, toku_fill_dbt(&k, "hello", 6), toku_fill_dbt(&v, "there", 6), null_txn);
186     }
187 
188     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
189     toku_cachetable_close(&ct);
190 
191     /* Now see if we can read it in and get the value. */
192     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
193     r = toku_open_ft_handle(fname, 0, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0);
194 
195     ft_lookup_and_check_nodup(ft, "hello", "there");
196 
197     assert(toku_verify_ft(ft)==0);
198 
199     /* Now put a bunch (NVALS) of things in. */
200     {
201 	int i;
202 	for (i=0; i<NVALS; i++) {
203 	    char key[100],val[100];
204 	    DBT k,v;
205 	    snprintf(key, 100, "key%d", i);
206 	    snprintf(val, 100, "val%d", i);
207 	    if (i<600) {
208 		int verify_result=toku_verify_ft(ft);;
209 		assert(verify_result==0);
210 	    }
211 	    toku_ft_insert(ft, toku_fill_dbt(&k, key, strlen(key)+1), toku_fill_dbt(&v, val, strlen(val)+1), null_txn);
212 	    if (i<600) {
213 		int verify_result=toku_verify_ft(ft);
214 		if (verify_result) {
215 		    r = toku_dump_ft(stdout, ft);
216 		    assert(r==0);
217 		    assert(0);
218 		}
219 		{
220 		    int j;
221 		    for (j=0; j<=i; j++) {
222 			char expectedval[100];
223 			snprintf(key, 100, "key%d", j);
224 			snprintf(expectedval, 100, "val%d", j);
225 			ft_lookup_and_check_nodup(ft, key, expectedval);
226 		    }
227 		}
228 	    }
229 	}
230     }
231     if (verbose) printf("Now read them out\n");
232 
233     r = toku_verify_ft(ft);
234     assert(r==0);
235     //dump_ft(ft);
236 
237     /* See if we can read them all out again. */
238     {
239 	int i;
240 	for (i=0; i<NVALS; i++) {
241 	    char key[100],expectedval[100];
242 	    snprintf(key, 100, "key%d", i);
243 	    snprintf(expectedval, 100, "val%d", i);
244 	    ft_lookup_and_check_nodup(ft, key, expectedval);
245 	}
246     }
247 
248     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
249     if (verbose) printf("%s:%d About to close %p\n", __FILE__, __LINE__, ct);
250     toku_cachetable_close(&ct);
251 
252 
253 
254     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
255     r = toku_open_ft_handle(fname, 0, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun); assert(r==0);
256 
257     ft_lookup_and_check_nodup(ft, "hello", "there");
258     {
259 	int i;
260 	for (i=0; i<NVALS; i++) {
261 	    char key[100],expectedval[100];
262 	    snprintf(key, 100, "key%d", i);
263 	    snprintf(expectedval, 100, "val%d", i);
264 	    ft_lookup_and_check_nodup(ft, key, expectedval);
265 	}
266     }
267 
268     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
269     toku_cachetable_close(&ct);
270 
271 
272 
273 
274     if (verbose) printf(" ok\n");
275 }
276 
277 /* Test c_get(DB_LAST) on an empty tree */
278 static void test_cursor_last_empty(void) {
279     CACHETABLE ct;
280     FT_HANDLE ft;
281     FT_CURSOR cursor=0;
282     int r;
encode_not_indexed2( name: &[u8], value: &[u8], sensitive: bool, dst: &mut DstBuf<'_>, ) -> Result<(), EncoderError>283     if (verbose) printf("%s", __FUNCTION__);
284     unlink(fname);
285 
286     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
287     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
288     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
289     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);  assert(r==0);
290     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
291     r = toku_ft_cursor(ft, &cursor, NULL, false, false);            assert(r==0);
292     {
293 	struct check_pair pair = {0,0,0,0,0};
294 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_LAST);
295 	assert(pair.call_count==0);
296 	assert(r==DB_NOTFOUND);
297     }
298     {
299 	struct check_pair pair = {0,0,0,0,0};
300 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
301 	assert(pair.call_count==0);
302 	assert(r==DB_NOTFOUND);
303     }
encode_str(val: &[u8], dst: &mut DstBuf<'_>) -> Result<(), EncoderError>304     toku_ft_cursor_close(cursor);
305     r = toku_close_ft_handle_nolsn(ft, 0);
306     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
307     toku_cachetable_close(&ct);
308     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
309 
310 }
311 
312 static void test_cursor_next (void) {
313     CACHETABLE ct;
314     FT_HANDLE ft;
315     FT_CURSOR cursor=0;
316     int r;
317     DBT kbt, vbt;
318 
319     unlink(fname);
320 
321     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
322     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
323     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);  assert(r==0);
324     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
325     toku_ft_insert(ft, toku_fill_dbt(&kbt, "hello", 6), toku_fill_dbt(&vbt, "there", 6), null_txn);
326     toku_ft_insert(ft, toku_fill_dbt(&kbt, "byebye", 7), toku_fill_dbt(&vbt, "byenow", 7), null_txn);
327     if (verbose) printf("%s:%d calling toku_ft_cursor(...)\n", __FILE__, __LINE__);
328     r = toku_ft_cursor(ft, &cursor, NULL, false, false);            assert(r==0);
329     toku_init_dbt(&kbt);
330     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
331     toku_init_dbt(&vbt);
332     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
333 
334     if (verbose) printf("%s:%d calling toku_ft_cursor_get(...)\n", __FILE__, __LINE__);
335     {
336 	struct check_pair pair = {7, "byebye", 7, "byenow", 0};
337 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
338 	if (verbose) printf("%s:%d called toku_ft_cursor_get(...)\n", __FILE__, __LINE__);
339 	assert(r==0);
340 	assert(pair.call_count==1);
341     }
342 
343     {
344 	struct check_pair pair = {6, "hello", 6, "there", 0};
345 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
346 	assert(r==0);
347 	assert(pair.call_count==1);
348     }
349     {
350 	struct check_pair pair = {0, 0, 0, 0, 0};
351 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
352 	assert(r==DB_NOTFOUND);
353 	assert(pair.call_count==0);
354     }
355 
356     toku_ft_cursor_close(cursor);
357     r = toku_close_ft_handle_nolsn(ft, 0);
358     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
359     toku_cachetable_close(&ct);
360     //printf("%s:%d %d alloced\n", __FILE__, __LINE__, toku_get_n_items_malloced()); toku_print_malloced_items();
361 
362 
encode_int<B: BufMut>( mut value: usize, prefix_bits: usize, first_byte: u8, dst: &mut B, ) -> Result<(), EncoderError>363 }
364 
365 static int wrong_compare_fun(DB* UU(desc), const DBT *a, const DBT *b) {
366     unsigned int i;
367     unsigned char *CAST_FROM_VOIDP(ad, a->data);
368     unsigned char *CAST_FROM_VOIDP(bd, b->data);
369     unsigned int siz=a->size;
370     assert(a->size==b->size);
371     //assert(db==&nonce_db); // make sure the db was passed  down correctly
372     for (i=0; i<siz; i++) {
373 	if (ad[siz-1-i]<bd[siz-1-i]) return -1;
374 	if (ad[siz-1-i]>bd[siz-1-i]) return +1;
375     }
376     return 0;
377 
378 }
379 
380 static void test_wrongendian_compare (int wrong_p, unsigned int N) {
381     CACHETABLE ct;
382     FT_HANDLE ft;
383     int r;
384     unsigned int i;
385 
386     unlink(fname);
387 
388 
389     {
390 	char a[4]={0,1,0,0};
391 	char b[4]={1,0,0,0};
392 	DBT at, bt;
393 	assert(wrong_compare_fun(NULL, toku_fill_dbt(&at, a, 4), toku_fill_dbt(&bt, b, 4))>0);
394 	assert(wrong_compare_fun(NULL, toku_fill_dbt(&at, b, 4), toku_fill_dbt(&bt, a, 4))<0);
395     }
396 
397     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
398     //printf("%s:%d WRONG=%d\n", __FILE__, __LINE__, wrong_p);
399 
400     if (0) { // ???? Why is this commented out?
401         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);
402     for (i=1; i<257; i+=255) {
403 	unsigned char a[4],b[4];
404 	b[3] = a[0] = (unsigned char)(i&255);
405 	b[2] = a[1] = (unsigned char)((i>>8)&255);
406 	b[1] = a[2] = (unsigned char)((i>>16)&255);
407 	b[0] = a[3] = (unsigned char)((i>>24)&255);
408 	DBT kbt;
409         toku_fill_dbt(&kbt, a, sizeof a);
410 	DBT vbt;
411         toku_fill_dbt(&vbt, b, sizeof b);
encode_int_one_byte(value: usize, prefix_bits: usize) -> bool412 	if (verbose)
413 	    printf("%s:%d insert: %02x%02x%02x%02x -> %02x%02x%02x%02x\n", __FILE__, __LINE__,
414 		   ((char*)kbt.data)[0], ((char*)kbt.data)[1], ((char*)kbt.data)[2], ((char*)kbt.data)[3],
415 		   ((char*)vbt.data)[0], ((char*)vbt.data)[1], ((char*)vbt.data)[2], ((char*)vbt.data)[3]);
position(buf: &DstBuf<'_>) -> usize416 	toku_ft_insert(ft, &kbt, &vbt, null_txn);
417     }
418     {
419 	FT_CURSOR cursor=0;
rewind(buf: &mut DstBuf<'_>, pos: usize)420 	r = toku_ft_cursor(ft, &cursor, NULL, false, false);            assert(r==0);
421 
422 	for (i=0; i<2; i++) {
423 	    unsigned char a[4],b[4];
424 	    struct check_pair pair = {4, &a, 4, &b, 0};
425 	    b[3] = a[0] = (unsigned char)(i&255);
426 	    b[2] = a[1] = (unsigned char)((i>>8)&255);
427 	    b[1] = a[2] = (unsigned char)((i>>16)&255);
428 	    b[0] = a[3] = (unsigned char)((i>>24)&255);
429 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
430 	    assert(r==0);
431 	    assert(pair.call_count==1);
test_encode_method_get()432 	}
433 
434 
435         r = toku_close_ft_handle_nolsn(ft, 0);
436     }
437     }
438 
439     {
test_encode_method_post()440 	toku_cachetable_verify(ct);
441 	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);
442 	toku_cachetable_verify(ct);
443 
444 	for (i=0; i<N; i++) {
445 	    unsigned char a[4],b[4];
446 	    b[3] = a[0] = (unsigned char)(i&255);
447 	    b[2] = a[1] = (unsigned char)((i>>8)&255);
test_encode_method_patch()448 	    b[1] = a[2] = (unsigned char)((i>>16)&255);
449 	    b[0] = a[3] = (unsigned char)((i>>24)&255);
450 	    DBT kbt;
451             toku_fill_dbt(&kbt, a, sizeof a);
452 	    DBT vbt;
453             toku_fill_dbt(&vbt, b, sizeof b);
454 	    if (0) printf("%s:%d insert: %02x%02x%02x%02x -> %02x%02x%02x%02x\n", __FILE__, __LINE__,
455 			  ((unsigned char*)kbt.data)[0], ((unsigned char*)kbt.data)[1], ((unsigned char*)kbt.data)[2], ((unsigned char*)kbt.data)[3],
456 			  ((unsigned char*)vbt.data)[0], ((unsigned char*)vbt.data)[1], ((unsigned char*)vbt.data)[2], ((unsigned char*)vbt.data)[3]);
457 	    toku_ft_insert(ft, &kbt, &vbt, null_txn);
458 	    toku_cachetable_verify(ct);
459 	}
460 	FT_CURSOR cursor=0;
461 	r = toku_ft_cursor(ft, &cursor, NULL, false, false);            assert(r==0);
462 
463 	for (i=0; i<N; i++) {
464 	    unsigned char a[4],b[4];
test_encode_indexed_name_literal_value()465 	    struct check_pair pair = {4, &a, 4, &b, 0};
466 	    b[3] = a[0] = (unsigned char)(i&255);
467 	    b[2] = a[1] = (unsigned char)((i>>8)&255);
468 	    b[1] = a[2] = (unsigned char)((i>>16)&255);
469 	    b[0] = a[3] = (unsigned char)((i>>24)&255);
470 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
471 	    assert(r==0);
472 	    assert(pair.call_count==1);
473 	    toku_cachetable_verify(ct);
474 	}
475         toku_ft_cursor_close(cursor);
476 	r = toku_close_ft_handle_nolsn(ft, 0);
477 	assert(r==0);
478     }
479     toku_cachetable_close(&ct);
480 
481 }
test_repeated_headers_are_indexed()482 
483 static int test_ft_cursor_keycompare(DB *desc __attribute__((unused)), const DBT *a, const DBT *b) {
484     return toku_keycompare(a->data, a->size, b->data, b->size);
485 }
486 
487 static void test_large_kv(int bsize, int ksize, int vsize) {
488     FT_HANDLE t;
489     int r;
490     CACHETABLE ct;
491 
492     if (verbose) printf("test_large_kv: %d %d %d\n", bsize, ksize, vsize);
493 
494     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
495     unlink(fname);
496     r = toku_open_ft_handle(fname, 1, &t, bsize, bsize / 4, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
497     assert(r==0);
498 
499     DBT key, val;
500     char *k, *v;
test_evicting_headers()501     XCALLOC_N(ksize, k);
502     XCALLOC_N(vsize, v);
503     toku_fill_dbt(&key, k, ksize);
504     toku_fill_dbt(&val, v, vsize);
505 
506     toku_ft_insert(t, &key, &val, 0);
507 
508     toku_free(k);
509     toku_free(v);
510 
511     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
512     toku_cachetable_close(&ct);
513 }
514 
515 /*
516  * test the key and value limits
517  * the current implementation crashes when kvsize == bsize/2 rather than fails
518  */
519 static void test_ft_limits(void) {
520     int bsize = 1024;
521     int kvsize = 4;
522     while (kvsize < bsize/2) {
523         test_large_kv(bsize, kvsize, kvsize);
524         kvsize *= 2;
525     }
526 }
527 
528 /*
529  * verify that a delete on an empty tree fails
530  */
531 static void test_ft_delete_empty(void) {
532     if (verbose) printf("test_ft_delete_empty\n");
533 
534     FT_HANDLE t;
535     int r;
536     CACHETABLE ct;
537 
538     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
539     unlink(fname);
540     r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
541     assert(r==0);
542 
543     DBT key;
544     int k = toku_htonl(1);
545     toku_fill_dbt(&key, &k, sizeof k);
546     toku_ft_delete(t, &key, null_txn);
547 
548     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
549     toku_cachetable_close(&ct);
550 }
551 
552 /*
test_large_headers_are_not_indexed()553  * insert n keys, delete all n keys, verify that lookups for all the keys fail,
554  * verify that a cursor walk of the tree finds nothing
555  */
556 static void test_ft_delete_present(int n) {
557     if (verbose) printf("test_ft_delete_present:%d\n", n);
558 
559     FT_HANDLE t;
560     int r;
561     CACHETABLE ct;
562     int i;
563 
564     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
565     unlink(fname);
566     r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
567     assert(r==0);
568 
569     /* insert 0 .. n-1 */
570     for (i=0; i<n; i++) {
571         int k = toku_htonl(i);
572 	int v = i;
573 	DBT key;
574         toku_fill_dbt(&key, &k, sizeof k);
575 	DBT val;
576         toku_fill_dbt(&val, &v, sizeof v);
577         toku_ft_insert(t, &key, &val, 0);
578     }
579 
580     /* delete 0 .. n-1 */
581     for (i=0; i<n; i++) {
582         int k = toku_htonl(i);
583 	DBT key;
584         toku_fill_dbt(&key, &k, sizeof k);
585         toku_ft_delete(t, &key, null_txn);
586         assert(r == 0);
587     }
588 
589     /* lookups should all fail */
590     for (i=0; i<n; i++) {
591         int k = toku_htonl(i);
592 	DBT key;
593         toku_fill_dbt(&key, &k, sizeof k);
594 	struct check_pair pair = {0, 0, 0, 0, 0};
595         r = toku_ft_lookup(t, &key, lookup_checkf, &pair);
596         assert(r == DB_NOTFOUND);
597 	assert(pair.call_count==0);
598     }
599 
600     /* cursor should not find anything */
601     FT_CURSOR cursor=0;
602 
603     r = toku_ft_cursor(t, &cursor, NULL, false, false);
604     assert(r == 0);
605 
606     {
607 	struct check_pair pair = {0,0,0,0,0};
608 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
609 	assert(r != 0);
610 	assert(pair.call_count==0);
611     }
612 
613     toku_ft_cursor_close(cursor);
614 
615     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
616     toku_cachetable_close(&ct);
617 }
618 
619 static void test_ft_delete_not_present(int n) {
620     if (verbose) printf("test_ft_delete_not_present:%d\n", n);
621 
622     FT_HANDLE t;
623     int r;
624     CACHETABLE ct;
625     int i;
626 
627     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
628     unlink(fname);
test_content_length_value_not_indexed()629     r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
630     assert(r==0);
631 
632     DBT key, val;
633     int k, v;
634 
635     /* insert 0 .. n-1 */
636     for (i=0; i<n; i++) {
637         k = toku_htonl(i); v = i;
638         toku_fill_dbt(&key, &k, sizeof k);
test_encoding_headers_with_same_name()639         toku_fill_dbt(&val, &v, sizeof v);
640         toku_ft_insert(t, &key, &val, 0);
641     }
642 
643     /* delete 0 .. n-1 */
644     for (i=0; i<n; i++) {
645         k = toku_htonl(i);
646         toku_fill_dbt(&key, &k, sizeof k);
647         toku_ft_delete(t, &key, null_txn);
648         assert(r == 0);
649     }
650 
651     /* try to delete key n+1 not in the tree */
652     k = toku_htonl(n+1);
653     toku_fill_dbt(&key, &k, sizeof k);
654     toku_ft_delete(t, &key, null_txn);
655     /* the delete may be buffered or may be executed on a leaf node, so the
656        return value depends */
657     if (verbose) printf("toku_ft_delete k=%d %d\n", k, r);
658 
659     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
660     toku_cachetable_close(&ct);
661 }
test_evicting_headers_when_multiple_of_same_name_are_in_table()662 
663 static void test_ft_delete_cursor_first(int n) {
664     if (verbose) printf("test_ft_delete_cursor_first:%d\n", n);
665 
666     FT_HANDLE t;
667     int r;
668     CACHETABLE ct;
669     int i;
670 
671     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
672     unlink(fname);
673     r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
674     assert(r==0);
675 
676     /* insert 0 .. n-1 */
677     for (i=0; i<n; i++) {
678         int k = toku_htonl(i);
679 	int v = i;
680 	DBT key;
681         toku_fill_dbt(&key, &k, sizeof k);
682 	DBT val;
683         toku_fill_dbt(&val, &v, sizeof v);
684         toku_ft_insert(t, &key, &val, 0);
685     }
686 
687     /* lookups 0 .. n-1 should succeed */
688     for (i=0; i<n; i++) {
689         int k = toku_htonl(i);
690 	DBT key;
691         toku_fill_dbt(&key, &k, sizeof k);
692 	int k2 = k;
693 	int v = i;
694 	struct check_pair pair = {sizeof k, &k2, sizeof v, &v, 0};
695         r = toku_ft_lookup(t, &key, lookup_checkf, &pair);
696         assert(r == 0);
697 	assert(pair.call_count==1);
698     }
699 
700     /* delete 0 .. n-2 */
701     for (i=0; i<n-1; i++) {
702 	{
703 	    int k = toku_htonl(i);
704 	    DBT key;
705             toku_fill_dbt(&key, &k, sizeof k);
706 	    toku_ft_delete(t, &key, null_txn);
707 	}
708 
709 	{
710 	    int k = toku_htonl(i);
711 	    DBT key;
712             toku_fill_dbt(&key, &k, sizeof k);
713 	    struct check_pair pair = {0,0,0,0,0};
714 	    r = toku_ft_lookup(t, &key, lookup_checkf, &pair);
715 	    assert(r == DB_NOTFOUND);
716 	    assert(pair.call_count==0);
717 	}
718     }
719 
720     /* lookup of 0 .. n-2 should all fail */
721     for (i=0; i<n-1; i++) {
722         int k = toku_htonl(i);
723 	DBT key;
724         toku_fill_dbt(&key, &k, sizeof k);
725 	struct check_pair pair = {0,0,0,0,0};
726         r = toku_ft_lookup(t, &key, lookup_checkf, &pair);
727         assert(r == DB_NOTFOUND);
728 	assert(pair.call_count==0);
729     }
730 
731     /* cursor should find the last key: n-1 */
732     FT_CURSOR cursor=0;
733 
734     r = toku_ft_cursor(t, &cursor, NULL, false, false);
735     assert(r == 0);
736 
737     {
738 	int kv = toku_htonl(n-1);
739 	int vv = n-1;
740 	struct check_pair pair = {sizeof kv, &kv, sizeof vv, &vv, 0};
741 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
742 	assert(r == 0);
743 	assert(pair.call_count==1);
744     }
745 
746     toku_ft_cursor_close(cursor);
747 
748     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
749     toku_cachetable_close(&ct);
750 }
751 
752 /* test for bug: insert message in a nonleaf node, delete removes the
753    insert message, but lookup finds the insert message
754 
755    build a 2 level tree, and expect the last insertion to be
756    buffered. then delete and lookup. */
757 
758 static void test_insert_delete_lookup(int n) {
759     if (verbose) printf("test_insert_delete_lookup:%d\n", n);
760 
761     FT_HANDLE t;
762     int r;
763     CACHETABLE ct;
test_decreasing_table_size_without_eviction()764     int i;
765 
766     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
767     unlink(fname);
768     r = toku_open_ft_handle(fname, 1, &t, 4096, 1024, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
769     assert(r==0);
770 
771     /* insert 0 .. n-1 */
772     for (i=0; i<n; i++) {
773         int k = toku_htonl(i);
774 	int v = i;
775 	DBT key;
776         toku_fill_dbt(&key, &k, sizeof k);
777 	DBT val;
test_nameless_header()778         toku_fill_dbt(&val, &v, sizeof v);
779         toku_ft_insert(t, &key, &val, 0);
780     }
781 
782     if (n > 0) {
783 	{
784 	    int k = toku_htonl(n-1);
785 	    DBT key;
786             toku_fill_dbt(&key, &k, sizeof k);
787 	    toku_ft_delete(t, &key, null_txn);
788 	}
789 	{
790 	    int k = toku_htonl(n-1);
791 	    DBT key;
792             toku_fill_dbt(&key, &k, sizeof k);
793 	    struct check_pair pair = {0,0,0,0,0};
794 	    r = toku_ft_lookup(t, &key, lookup_checkf, &pair);
795 	    assert(r == DB_NOTFOUND);
796 	    assert(pair.call_count==0);
797 	}
798     }
799 
800     r = toku_close_ft_handle_nolsn(t, 0);        assert(r==0);
801     toku_cachetable_close(&ct);
802 }
803 
804 /* insert <0,0>, <0,1>, .. <0,n>
805    delete_both <0,i> for all even i
test_nameless_header_at_resume()806    verify <0,i> exists for all odd i */
807 
808 
809 static void test_ft_delete(void) {
810     test_ft_delete_empty();
811     test_ft_delete_present(1);
812     test_ft_delete_present(100);
813     test_ft_delete_present(500);
814     test_ft_delete_not_present(1);
815     test_ft_delete_not_present(100);
816     test_ft_delete_not_present(500);
817     test_ft_delete_cursor_first(1);
818     test_ft_delete_cursor_first(100);
819     test_ft_delete_cursor_first(500);
820     test_ft_delete_cursor_first(10000);
821     test_insert_delete_lookup(2);
822     test_insert_delete_lookup(512);
823 }
824 
825 static void test_new_ft_cursor_create_close (void) {
826     int r;
827     FT_HANDLE ft=0;
828     int n = 8;
829     FT_CURSOR cursors[n];
830 
831     toku_ft_handle_create(&ft);
832 
833     int i;
834     for (i=0; i<n; i++) {
835         r = toku_ft_cursor(ft, &cursors[i], NULL, false, false); assert(r == 0);
836     }
837 
838     for (i=0; i<n; i++) {
839         toku_ft_cursor_close(cursors[i]);
840     }
841 
842     r = toku_close_ft_handle_nolsn(ft, 0); assert(r == 0);
843 }
844 
845 static void test_new_ft_cursor_first(int n) {
846     if (verbose) printf("test_ft_cursor_first:%d\n", n);
847 
848     FT_HANDLE t=0;
849     int r;
850     CACHETABLE ct;
851     int i;
852 
test_evicted_overflow()853     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
854     unlink(fname);
855     toku_ft_handle_create(&t);
856     toku_ft_handle_set_nodesize(t, 4096);
encode(e: &mut Encoder, hdrs: Vec<Header<Option<HeaderName>>>) -> BytesMut857     r = toku_ft_handle_open(t, fname, 1, 1, ct, null_txn); assert(r==0);
858 
859     DBT key, val;
860     int k, v;
861 
862     for (i=0; i<n; i++) {
method(s: &str) -> Header<Option<HeaderName>>863         k = toku_htonl(i); v = toku_htonl(i);
864         toku_ft_insert(t, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
865     }
866 
header(name: &str, val: &str) -> Header<Option<HeaderName>>867     FT_CURSOR cursor=0;
868 
869     r = toku_ft_cursor(t, &cursor, NULL, false, false); assert(r == 0);
870 
871     toku_init_dbt(&key); key.flags = DB_DBT_REALLOC;
872     toku_init_dbt(&val); val.flags = DB_DBT_REALLOC;
873 
874     for (i=0; ; i++) {
875 	int kv = toku_htonl(i);
876 	int vv = toku_htonl(i);
huff_decode(src: &[u8]) -> BytesMut877 	struct check_pair pair = {sizeof kv, &kv, sizeof vv, &vv, 0};
878         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
879         if (r != 0) {
880 	    assert(pair.call_count==0);
881 	    break;
882 	}
883 	assert(pair.call_count==1);
884 
885         r = toku_ft_cursor_delete(cursor, 0, null_txn); assert(r == 0);
886     }
887     assert(i == n);
888 
889     if (key.data) toku_free(key.data);
890     if (val.data) toku_free(val.data);
891 
892     toku_ft_cursor_close(cursor);
893     r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
894     toku_cachetable_close(&ct);
895 }
896 
897 static void test_new_ft_cursor_last(int n) {
898     if (verbose) printf("test_ft_cursor_last:%d\n", n);
899 
900     FT_HANDLE t=0;
901     int r;
902     CACHETABLE ct;
903     int i;
904 
905     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
906     unlink(fname);
907     toku_ft_handle_create(&t);
908     toku_ft_handle_set_nodesize(t, 4096);
909     r = toku_ft_handle_open(t, fname, 1, 1, ct, null_txn); assert(r==0);
910 
911     DBT key, val;
912     int k, v;
913 
914     for (i=0; i<n; i++) {
915         k = toku_htonl(i); v = toku_htonl(i);
916         toku_ft_insert(t, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
917     }
918 
919     FT_CURSOR cursor=0;
920 
921     r = toku_ft_cursor(t, &cursor, NULL, false, false); assert(r == 0);
922 
923     toku_init_dbt(&key); key.flags = DB_DBT_REALLOC;
924     toku_init_dbt(&val); val.flags = DB_DBT_REALLOC;
925 
926     for (i=n-1; ; i--) {
927 	int kk = toku_htonl(i);
928 	int vv = toku_htonl(i);
929 	struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
930         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_LAST);
931         if (r != 0) {
932 	    assert(pair.call_count==0);
933 	    break;
934 	}
935 	assert(pair.call_count==1);
936 
937 	//if (n==512 && i<=360) { printf("i=%d\n", i); toku_dump_ft(stdout, t); }
938         r = toku_ft_cursor_delete(cursor, 0, null_txn); assert(r == 0);
939     }
940     assert(i == -1);
941 
942     if (key.data) toku_free(key.data);
943     if (val.data) toku_free(val.data);
944 
945     toku_ft_cursor_close(cursor);
946     r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
947     toku_cachetable_close(&ct);
948 }
949 
950 static void test_new_ft_cursor_next(int n) {
951     if (verbose) printf("test_ft_cursor_next:%d\n", n);
952 
953     FT_HANDLE t=0;
954     int r;
955     CACHETABLE ct;
956     int i;
957 
958     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
959     unlink(fname);
960     toku_ft_handle_create(&t);
961     toku_ft_handle_set_nodesize(t, 4096);
962     r = toku_ft_handle_open(t, fname, 1, 1, ct, null_txn); assert(r==0);
963 
964     for (i=0; i<n; i++) {
965 	DBT key, val;
966 	int k = toku_htonl(i);
967 	int v = toku_htonl(i);
968         toku_ft_insert(t, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
969     }
970 
971     FT_CURSOR cursor=0;
972 
973     r = toku_ft_cursor(t, &cursor, NULL, false, false); assert(r == 0);
974 
975     for (i=0; ; i++) {
976 	int kk = toku_htonl(i);
977 	int vv = toku_htonl(i);
978 	struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
979         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
980         if (r != 0) {
981 	    assert(pair.call_count ==0);
982 	    break;
983 	}
984 	assert(pair.call_count==1);
985     }
986     assert(i == n);
987 
988     toku_ft_cursor_close(cursor);
989     r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
990     toku_cachetable_close(&ct);
991 }
992 
993 static void test_new_ft_cursor_prev(int n) {
994     if (verbose) printf("test_ft_cursor_prev:%d\n", n);
995 
996     FT_HANDLE t=0;
997     int r;
998     CACHETABLE ct;
999     int i;
1000 
1001     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
1002     unlink(fname);
1003     toku_ft_handle_create(&t);
1004     toku_ft_handle_set_nodesize(t, 4096);
1005     r = toku_ft_handle_open(t, fname, 1, 1, ct, null_txn); assert(r==0);
1006 
1007     for (i=0; i<n; i++) {
1008 	DBT key, val;
1009         int k = toku_htonl(i);
1010 	int v = toku_htonl(i);
1011         toku_ft_insert(t, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
1012     }
1013 
1014     FT_CURSOR cursor=0;
1015 
1016     r = toku_ft_cursor(t, &cursor, NULL, false, false); assert(r == 0);
1017 
1018     for (i=n-1; ; i--) {
1019 	int kk = toku_htonl(i);
1020 	int vv = toku_htonl(i);
1021 	struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
1022         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_PREV);
1023         if (r != 0) {
1024 	    assert(pair.call_count==0);
1025 	    break;
1026 	}
1027 	assert(pair.call_count==1);
1028     }
1029     assert(i == -1);
1030 
1031     toku_ft_cursor_close(cursor);
1032     r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
1033     toku_cachetable_close(&ct);
1034 }
1035 
1036 static void test_new_ft_cursor_current(int n) {
1037     if (verbose) printf("test_ft_cursor_current:%d\n", n);
1038 
1039     FT_HANDLE t=0;
1040     int r;
1041     CACHETABLE ct;
1042     int i;
1043 
1044     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
1045     unlink(fname);
1046     toku_ft_handle_create(&t);
1047     toku_ft_handle_set_nodesize(t, 4096);
1048     r = toku_ft_handle_open(t, fname, 1, 1, ct, null_txn); assert(r==0);
1049 
1050     for (i=0; i<n; i++) {
1051         int k = toku_htonl(i);
1052 	int v = toku_htonl(i);
1053 	DBT key, val;
1054         toku_ft_insert(t, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
1055     }
1056 
1057     FT_CURSOR cursor=0;
1058 
1059     r = toku_ft_cursor(t, &cursor, NULL, false, false); assert(r == 0);
1060 
1061     for (i=0; ; i++) {
1062 	{
1063 	    int kk = toku_htonl(i);
1064 	    int vv = toku_htonl(i);
1065 	    struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
1066 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
1067 	    if (r != 0) {
1068 		assert(pair.call_count==0);
1069 		break;
1070 	    }
1071 	    assert(pair.call_count==1);
1072 	}
1073 	{
1074 	    int kk = toku_htonl(i);
1075 	    int vv = toku_htonl(i);
1076 	    struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
1077 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_CURRENT);
1078 	    assert(r == 0);
1079 	    assert(pair.call_count==1);
1080 	}
1081 
1082 	{
1083 	    int kk = toku_htonl(i);
1084 	    int vv = toku_htonl(i);
1085 	    struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
1086 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_CURRENT_BINDING);
1087 	    assert(r == 0);
1088 	    assert(pair.call_count==1);
1089 	}
1090 
1091         r = toku_ft_cursor_delete(cursor, 0, null_txn); assert(r == 0);
1092 
1093 	{
1094 	    static int count=0;
1095 	    count++;
1096 	    struct check_pair pair = {0,0,0,0,0};
1097 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_CURRENT);
1098 	    CKERR2(r,DB_NOTFOUND); // previous DB_KEYEMPTY
1099 	    assert(pair.call_count==0);
1100 	}
1101 
1102 	{
1103 	    int kk = toku_htonl(i);
1104 	    int vv = toku_htonl(i);
1105 	    struct check_pair pair = {sizeof kk, &kk, sizeof vv, &vv, 0};
1106 	    r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_CURRENT_BINDING);
1107 	    assert(r == 0);
1108 	    assert(pair.call_count==1);
1109 	}
1110     }
1111     assert(i == n);
1112 
1113     toku_ft_cursor_close(cursor);
1114     r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
1115     toku_cachetable_close(&ct);
1116 }
1117 
1118 static void test_new_ft_cursor_set_range(int n) {
1119     if (verbose) printf("test_ft_cursor_set_range:%d\n", n);
1120 
1121     int r;
1122     CACHETABLE ct;
1123     FT_HANDLE ft=0;
1124     FT_CURSOR cursor=0;
1125 
1126     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
1127     unlink(fname);
1128     toku_ft_handle_create(&ft);
1129     toku_ft_handle_set_nodesize(ft, 4096);
1130     r = toku_ft_handle_open(ft, fname, 1, 1, ct, null_txn); assert(r==0);
1131 
1132     int i;
1133 
1134     /* insert keys 0, 10, 20 .. 10*(n-1) */
1135     int max_key = 10*(n-1);
1136     for (i=0; i<n; i++) {
1137 	DBT key, val;
1138         int k = toku_htonl(10*i);
1139         int v = 10*i;
1140         toku_ft_insert(ft, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
1141     }
1142 
1143     r = toku_ft_cursor(ft, &cursor, NULL, false, false); assert(r==0);
1144 
1145     /* pick random keys v in 0 <= v < 10*n, the cursor should point
1146        to the smallest key in the tree that is >= v */
1147     for (i=0; i<n; i++) {
1148 
1149         int v = random() % (10*n);
1150         int k = toku_htonl(v);
1151         DBT key;
1152         toku_fill_dbt(&key, &k, sizeof k);
1153 
1154 	int vv = (((v+9)/10)*10); // This is the value we should actually find.
1155 
1156 	struct check_pair pair = {sizeof k,  NULL,  // NULL data means don't check it
1157 				  sizeof vv,  &vv,
1158 				  0};
1159         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, DB_SET_RANGE);
1160         if (v > max_key) {
1161             /* there is no smallest key if v > the max key */
1162             assert(r == DB_NOTFOUND);
1163 	    assert(pair.call_count==0);
1164 	} else {
1165             assert(r == 0);
1166 	    assert(pair.call_count==1);
1167         }
1168     }
1169 
1170     toku_ft_cursor_close(cursor);
1171 
1172     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
1173 
1174     toku_cachetable_close(&ct);
1175 }
1176 
1177 static void test_new_ft_cursor_set(int n, int cursor_op, DB *db) {
1178     if (verbose) printf("test_ft_cursor_set:%d %d %p\n", n, cursor_op, db);
1179 
1180     int r;
1181     CACHETABLE ct;
1182     FT_HANDLE ft;
1183     FT_CURSOR cursor=0;
1184 
1185     unlink(fname);
1186 
1187     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
1188 
1189     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);
1190 
1191     int i;
1192 
1193     /* insert keys 0, 10, 20 .. 10*(n-1) */
1194     for (i=0; i<n; i++) {
1195 	DBT key, val;
1196         int k = toku_htonl(10*i);
1197         int v = 10*i;
1198         toku_ft_insert(ft, toku_fill_dbt(&key, &k, sizeof k), toku_fill_dbt(&val, &v, sizeof v), 0); assert(r == 0);
1199     }
1200 
1201     r = toku_ft_cursor(ft, &cursor, NULL, false, false); assert(r==0);
1202 
1203     /* set cursor to random keys in set { 0, 10, 20, .. 10*(n-1) } */
1204     for (i=0; i<n; i++) {
1205 
1206         int v = 10*(random() % n);
1207         int k = toku_htonl(v);
1208         DBT key;
1209         toku_fill_dbt(&key, &k, sizeof k);
1210 	struct check_pair pair = {sizeof k, &k, sizeof v, &v, 0};
1211         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, cursor_op);
1212         assert(r == 0);
1213 	assert(pair.call_count==1);
1214         if (cursor_op == DB_SET) assert(key.data == &k);
1215     }
1216 
1217     /* try to set cursor to keys not in the tree, all should fail */
1218     for (i=0; i<10*n; i++) {
1219         if (i % 10 == 0)
1220             continue;
1221         int k = toku_htonl(i);
1222         DBT key;
1223         toku_fill_dbt(&key, &k, sizeof k);
1224 	struct check_pair pair = {0,0,0,0,0};
1225         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, DB_SET);
1226         assert(r == DB_NOTFOUND);
1227 	assert(pair.call_count==0);
1228         assert(key.data == &k);
1229     }
1230 
1231     toku_ft_cursor_close(cursor);
1232 
1233     r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
1234 
1235     toku_cachetable_close(&ct);
1236 }
1237 
1238 static void test_new_ft_cursors(void) {
1239     test_new_ft_cursor_create_close();
1240     test_new_ft_cursor_first(8);
1241     test_new_ft_cursor_last(8);
1242     test_new_ft_cursor_last(512);
1243     test_new_ft_cursor_next(8);
1244     test_new_ft_cursor_prev(8);
1245     test_new_ft_cursor_current(8);
1246     test_new_ft_cursor_next(512);
1247     test_new_ft_cursor_set_range(512);
1248     test_new_ft_cursor_set(512, DB_SET, 0);
1249 }
1250 
1251 static void ft_blackbox_test (void) {
1252 
1253     test_wrongendian_compare(0, 2);
1254     test_wrongendian_compare(1, 2);
1255     test_wrongendian_compare(1, 257);
1256     test_wrongendian_compare(1, 1000);
1257     test_new_ft_cursors();
1258 
1259     test_read_what_was_written();          if (verbose) printf("did read_what_was_written\n");
1260     test_cursor_next();
1261     test_cursor_last_empty();
1262     test_multiple_ft_handles_one_db_one_file();
1263     test_dump_empty_db();
1264 
1265 
1266     if (verbose) printf("test_multiple_files\n");
1267     test_multiple_files();
1268 
1269     test_ft_limits();
1270 
1271     test_ft_delete();
1272 }
1273 
1274 int
1275 test_main (int argc , const char *argv[]) {
1276     default_parse_args(argc, argv);
1277 
1278     ft_blackbox_test();
1279     if (verbose) printf("test ok\n");
1280     return 0;
1281 }
1282