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 
39 #include "test.h"
40 
41 static const char *fname = TOKU_TEST_FILENAME;
42 
43 static TOKUTXN const null_txn = 0;
44 
45 static int test_cursor_debug = 0;
46 
test_ft_cursor_keycompare(DB * desc,const DBT * a,const DBT * b)47 static int test_ft_cursor_keycompare(DB *desc __attribute__((unused)), const DBT *a, const DBT *b) {
48     return toku_keycompare(a->data, a->size, b->data, b->size);
49 }
50 
assert_cursor_notfound(FT_HANDLE ft,int position)51 static void assert_cursor_notfound(FT_HANDLE ft, int position) {
52     FT_CURSOR cursor=0;
53     int r;
54 
55     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
56     assert(r==0);
57 
58     struct check_pair pair = {0,0,0,0,0};
59     r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, position);
60     assert(r == DB_NOTFOUND);
61     assert(pair.call_count==0);
62 
63     toku_ft_cursor_close(cursor);
64 }
65 
assert_cursor_value(FT_HANDLE ft,int position,long long value)66 static void assert_cursor_value(FT_HANDLE ft, int position, long long value) {
67     FT_CURSOR cursor=0;
68     int r;
69 
70     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
71     assert(r==0);
72 
73     if (test_cursor_debug && verbose) printf("key: ");
74     struct check_pair pair = {len_ignore, 0, sizeof(value), &value, 0};
75     r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, position);
76     assert(r == 0);
77     assert(pair.call_count==1);
78 
79     toku_ft_cursor_close(cursor);
80 }
81 
assert_cursor_first_last(FT_HANDLE ft,long long firstv,long long lastv)82 static void assert_cursor_first_last(FT_HANDLE ft, long long firstv, long long lastv) {
83     FT_CURSOR cursor=0;
84     int r;
85 
86     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
87     assert(r==0);
88 
89     if (test_cursor_debug && verbose) printf("first key: ");
90     {
91 	struct check_pair pair = {len_ignore, 0, sizeof(firstv), &firstv, 0};
92 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_FIRST);
93 	assert(r == 0);
94 	assert(pair.call_count==1);
95     }
96 
97     if (test_cursor_debug && verbose) printf("last key:");
98     {
99 	struct check_pair pair = {len_ignore, 0, sizeof(lastv), &lastv, 0};
100 	r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_LAST);
101 	assert(r == 0);
102 	assert(pair.call_count==1);
103     }
104     if (test_cursor_debug && verbose) printf("\n");
105 
106     toku_ft_cursor_close(cursor);
107 }
108 
test_ft_cursor_first(int n)109 static void test_ft_cursor_first(int n) {
110     CACHETABLE ct;
111     FT_HANDLE ft;
112     int r;
113     int i;
114 
115     if (verbose) printf("test_ft_cursor_first:%d\n", n);
116 
117     unlink(fname);
118 
119     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
120 
121     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
122     assert(r==0);
123 
124     /* insert a bunch of kv pairs */
125     for (i=0; i<n; i++) {
126         char key[8]; long long v;
127         DBT kbt, vbt;
128 
129         snprintf(key, sizeof key, "%4.4d", i);
130         toku_fill_dbt(&kbt, key, strlen(key)+1);
131         v = i;
132         toku_fill_dbt(&vbt, &v, sizeof v);
133         toku_ft_insert(ft, &kbt, &vbt, 0);
134     }
135 
136     if (n == 0)
137         assert_cursor_notfound(ft, DB_FIRST);
138     else
139         assert_cursor_value(ft, DB_FIRST, 0);
140 
141     r = toku_close_ft_handle_nolsn(ft, 0);
142     assert(r==0);
143 
144     toku_cachetable_close(&ct);
145 }
146 
test_ft_cursor_last(int n)147 static void test_ft_cursor_last(int n) {
148     CACHETABLE ct;
149     FT_HANDLE ft;
150     int r;
151     int i;
152 
153     if (verbose) printf("test_ft_cursor_last:%d\n", n);
154 
155     unlink(fname);
156 
157     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
158 
159     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
160     assert(r==0);
161 
162     /* insert keys 0, 1, .. (n-1) */
163     for (i=0; i<n; i++) {
164         char key[8]; long long v;
165         DBT kbt, vbt;
166 
167         snprintf(key, sizeof key, "%4.4d", i);
168         toku_fill_dbt(&kbt, key, strlen(key)+1);
169         v = i;
170         toku_fill_dbt(&vbt, &v, sizeof v);
171         toku_ft_insert(ft, &kbt, &vbt, 0);
172         assert(r==0);
173     }
174 
175     if (n == 0)
176         assert_cursor_notfound(ft, DB_LAST);
177     else
178         assert_cursor_value(ft, DB_LAST, n-1);
179 
180     r = toku_close_ft_handle_nolsn(ft, 0);
181     assert(r==0);
182 
183     toku_cachetable_close(&ct);
184 }
185 
test_ft_cursor_first_last(int n)186 static void test_ft_cursor_first_last(int n) {
187     CACHETABLE ct;
188     FT_HANDLE ft;
189     int r;
190     int i;
191 
192     if (verbose) printf("test_ft_cursor_first_last:%d\n", n);
193 
194     unlink(fname);
195 
196     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
197 
198     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
199     assert(r==0);
200 
201     /* insert a bunch of kv pairs */
202     for (i=0; i<n; i++) {
203         char key[8]; long long v;
204         DBT kbt, vbt;
205 
206         snprintf(key, sizeof key, "%4.4d", i);
207         toku_fill_dbt(&kbt, key, strlen(key)+1);
208         v = i;
209         toku_fill_dbt(&vbt, &v, sizeof v);
210 
211         toku_ft_insert(ft, &kbt, &vbt, 0);
212     }
213 
214     if (n == 0) {
215         assert_cursor_notfound(ft, DB_FIRST);
216         assert_cursor_notfound(ft, DB_LAST);
217     } else
218         assert_cursor_first_last(ft, 0, n-1);
219 
220     r = toku_close_ft_handle_nolsn(ft, 0);
221     assert(r==0);
222 
223     toku_cachetable_close(&ct);
224 
225 
226 }
227 
test_ft_cursor_rfirst(int n)228 static void test_ft_cursor_rfirst(int n) {
229     CACHETABLE ct;
230     FT_HANDLE ft;
231     int r;
232     int i;
233 
234     if (verbose) printf("test_ft_cursor_rfirst:%d\n", n);
235 
236     unlink(fname);
237 
238     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
239 
240     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
241     assert(r==0);
242 
243     /* insert keys n-1, n-2, ... , 0 */
244     for (i=n-1; i>=0; i--) {
245         char key[8]; long long v;
246         DBT kbt, vbt;
247 
248 
249         snprintf(key, sizeof key, "%4.4d", i);
250         toku_fill_dbt(&kbt, key, strlen(key)+1);
251         v = i;
252         toku_fill_dbt(&vbt, &v, sizeof v);
253         toku_ft_insert(ft, &kbt, &vbt, 0);
254     }
255 
256     if (n == 0)
257         assert_cursor_notfound(ft, DB_FIRST);
258     else
259         assert_cursor_value(ft, DB_FIRST, 0);
260 
261     r = toku_close_ft_handle_nolsn(ft, 0);
262     assert(r==0);
263 
264     toku_cachetable_close(&ct);
265 }
266 
assert_cursor_walk(FT_HANDLE ft,int n)267 static void assert_cursor_walk(FT_HANDLE ft, int n) {
268     FT_CURSOR cursor=0;
269     int i;
270     int r;
271 
272     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
273     assert(r==0);
274 
275     if (test_cursor_debug && verbose) printf("key: ");
276     for (i=0; ; i++) {
277         long long v = i;
278 	struct check_pair pair = {len_ignore, 0, sizeof(v), &v, 0};
279         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
280         if (r != 0) {
281 	    assert(pair.call_count==0);
282             break;
283 	}
284 	assert(pair.call_count==1);
285     }
286     if (test_cursor_debug && verbose) printf("\n");
287     assert(i == n);
288 
289     toku_ft_cursor_close(cursor);
290 }
291 
test_ft_cursor_walk(int n)292 static void test_ft_cursor_walk(int n) {
293     CACHETABLE ct;
294     FT_HANDLE ft;
295     int r;
296     int i;
297 
298     if (verbose) printf("test_ft_cursor_walk:%d\n", n);
299 
300     unlink(fname);
301 
302     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
303 
304     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
305     assert(r==0);
306 
307     /* insert a bunch of kv pairs */
308     for (i=0; i<n; i++) {
309         char key[8]; long long v;
310         DBT kbt, vbt;
311 
312         snprintf(key, sizeof key, "%4.4d", i);
313         toku_fill_dbt(&kbt, key, strlen(key)+1);
314         v = i;
315         toku_fill_dbt(&vbt, &v, sizeof v);
316         toku_ft_insert(ft, &kbt, &vbt, 0);
317     }
318 
319     /* walk the tree */
320     assert_cursor_walk(ft, n);
321 
322     r = toku_close_ft_handle_nolsn(ft, 0);
323     assert(r==0);
324 
325     toku_cachetable_close(&ct);
326 
327 }
328 
assert_cursor_rwalk(FT_HANDLE ft,int n)329 static void assert_cursor_rwalk(FT_HANDLE ft, int n) {
330     FT_CURSOR cursor=0;
331     int i;
332     int r;
333 
334     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
335     assert(r==0);
336 
337     if (test_cursor_debug && verbose) printf("key: ");
338     for (i=n-1; ; i--) {
339         long long v = i;
340 	struct check_pair pair = {len_ignore, 0, sizeof v, &v, 0};
341         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_PREV);
342         if (r != 0) {
343 	    assert(pair.call_count==0);
344             break;
345 	}
346 	assert(pair.call_count==1);
347     }
348     if (test_cursor_debug && verbose) printf("\n");
349     assert(i == -1);
350 
351     toku_ft_cursor_close(cursor);
352 }
353 
test_ft_cursor_rwalk(int n)354 static void test_ft_cursor_rwalk(int n) {
355     CACHETABLE ct;
356     FT_HANDLE ft;
357     int r;
358     int i;
359 
360     if (verbose) printf("test_ft_cursor_rwalk:%d\n", n);
361 
362     unlink(fname);
363 
364     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
365 
366     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
367     assert(r==0);
368 
369     /* insert a bunch of kv pairs */
370     for (i=0; i<n; i++) {
371         int k; long long v;
372         DBT kbt, vbt;
373 
374         k = toku_htonl(i);
375         toku_fill_dbt(&kbt, &k, sizeof k);
376         v = i;
377         toku_fill_dbt(&vbt, &v, sizeof v);
378         toku_ft_insert(ft, &kbt, &vbt, 0);
379     }
380 
381     /* walk the tree */
382     assert_cursor_rwalk(ft, n);
383 
384     r = toku_close_ft_handle_nolsn(ft, 0);
385     assert(r==0);
386 
387     toku_cachetable_close(&ct);
388 
389 }
390 
391 static int
ascending_key_string_checkf(uint32_t keylen,const void * key,uint32_t UU (vallen),const void * UU (val),void * v,bool lock_only)392 ascending_key_string_checkf (uint32_t keylen, const void *key, uint32_t UU(vallen), const void *UU(val), void *v, bool lock_only)
393 // the keys are strings.  Verify that they keylen matches the key, that the keys are ascending.  Use (char**)v  to hold a
394 // malloc'd previous string.
395 {
396     if (lock_only) return 0;
397     if (key!=NULL) {
398 	assert(keylen == 1+strlen((char*)key));
399 	char **CAST_FROM_VOIDP(prevkeyp, v);
400 	char *prevkey = *prevkeyp;
401 	if (prevkey!=0) {
402 	    assert(strcmp(prevkey, (char*)key)<0);
403 	    toku_free(prevkey);
404 	}
405 	*prevkeyp = toku_strdup((char*) key);
406     }
407     return 0;
408 }
409 
410 // The keys are strings (null terminated)
assert_cursor_walk_inorder(FT_HANDLE ft,int n)411 static void assert_cursor_walk_inorder(FT_HANDLE ft, int n) {
412     FT_CURSOR cursor=0;
413     int i;
414     int r;
415     char *prevkey = 0;
416 
417     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
418     assert(r==0);
419 
420     if (test_cursor_debug && verbose) printf("key: ");
421     for (i=0; ; i++) {
422         r = toku_ft_cursor_get(cursor, NULL, ascending_key_string_checkf, &prevkey, DB_NEXT);
423         if (r != 0) {
424             break;
425 	}
426 	assert(prevkey!=0);
427     }
428     if (prevkey) toku_free(prevkey);
429     if (test_cursor_debug && verbose) printf("\n");
430     assert(i == n);
431 
432     toku_ft_cursor_close(cursor);
433 }
434 
test_ft_cursor_rand(int n)435 static void test_ft_cursor_rand(int n) {
436     CACHETABLE ct;
437     FT_HANDLE ft;
438     int r;
439     int i;
440 
441     if (verbose) printf("test_ft_cursor_rand:%d\n", n);
442 
443     unlink(fname);
444 
445     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
446 
447     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
448     assert(r==0);
449 
450     /* insert a bunch of kv pairs */
451     for (i=0; i<n; i++) {
452         char key[8]; long long v;
453         DBT kbt, vbt;
454 
455         for (;;) {
456 	    v = ((long long) random() << 32) + random();
457 	    snprintf(key, sizeof key, "%lld", v);
458 	    toku_fill_dbt(&kbt, key, strlen(key)+1);
459 	    v = i;
460 	    toku_fill_dbt(&vbt, &v, sizeof v);
461 	    struct check_pair pair = {kbt.size, key, len_ignore, 0, 0};
462 	    r = toku_ft_lookup(ft, &kbt, lookup_checkf, &pair);
463 	    if (r == 0) {
464 		assert(pair.call_count==1);
465                 if (verbose) printf("dup");
466                 continue;
467 	    }
468 	    assert(pair.call_count==0);
469 	    toku_ft_insert(ft, &kbt, &vbt, 0);
470 	    break;
471         }
472     }
473 
474     /* walk the tree */
475     assert_cursor_walk_inorder(ft, n);
476 
477     r = toku_close_ft_handle_nolsn(ft, 0);
478     assert(r==0);
479 
480     toku_cachetable_close(&ct);
481 }
482 
test_ft_cursor_split(int n)483 static void test_ft_cursor_split(int n) {
484     CACHETABLE ct;
485     FT_HANDLE ft;
486     FT_CURSOR cursor=0;
487     int r;
488     int keyseqnum;
489     int i;
490 
491     if (verbose) printf("test_ft_cursor_split:%d\n", n);
492 
493     unlink(fname);
494 
495     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
496 
497     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
498     assert(r==0);
499 
500     /* insert a bunch of kv pairs */
501     for (keyseqnum=0; keyseqnum < n/2; keyseqnum++) {
502 	DBT kbt, vbt;
503         char key[8]; long long v;
504 
505         snprintf(key, sizeof key, "%4.4d", keyseqnum);
506         toku_fill_dbt(&kbt, key, strlen(key)+1);
507         v = keyseqnum;
508         toku_fill_dbt(&vbt, &v, sizeof v);
509         toku_ft_insert(ft, &kbt, &vbt, 0);
510     }
511 
512     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
513     assert(r==0);
514 
515     if (test_cursor_debug && verbose) printf("key: ");
516     for (i=0; i<n/2; i++) {
517 	struct check_pair pair = {len_ignore, 0, len_ignore, 0, 0};
518         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
519         assert(r==0);
520 	assert(pair.call_count==1);
521     }
522     if (test_cursor_debug && verbose) printf("\n");
523 
524     for (; keyseqnum<n; keyseqnum++) {
525 	DBT kbt,vbt;
526         char key[8]; long long v;
527 
528         snprintf(key, sizeof key, "%4.4d", keyseqnum);
529         toku_fill_dbt(&kbt, key, strlen(key)+1);
530         v = keyseqnum;
531         toku_fill_dbt(&vbt, &v, sizeof v);
532         toku_ft_insert(ft, &kbt, &vbt, 0);
533     }
534 
535     if (test_cursor_debug && verbose) printf("key: ");
536     // Just loop through the cursor
537     for (;;) {
538 	struct check_pair pair = {len_ignore, 0, len_ignore, 0, 0};
539         r = toku_ft_cursor_get(cursor, NULL, lookup_checkf, &pair, DB_NEXT);
540         if (r != 0) {
541 	    assert(pair.call_count==0);
542             break;
543 	}
544 	assert(pair.call_count==1);
545     }
546     if (test_cursor_debug && verbose) printf("\n");
547 
548     toku_ft_cursor_close(cursor);
549 
550     r = toku_close_ft_handle_nolsn(ft, 0);
551     assert(r==0);
552 
553     toku_cachetable_close(&ct);
554 }
555 
test_multiple_ft_cursors(int n)556 static void test_multiple_ft_cursors(int n) {
557     if (verbose) printf("test_multiple_ft_cursors:%d\n", n);
558 
559     int r;
560     CACHETABLE ct;
561     FT_HANDLE ft;
562     FT_CURSOR cursors[n];
563 
564     unlink(fname);
565 
566     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
567 
568     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
569     assert(r==0);
570 
571     int i;
572     for (i=0; i<n; i++) {
573         r = toku_ft_cursor(ft, &cursors[i], NULL, false, false);
574         assert(r == 0);
575     }
576 
577     for (i=0; i<n; i++) {
578         toku_ft_cursor_close(cursors[i]);
579     }
580 
581     r = toku_close_ft_handle_nolsn(ft, 0);
582     assert(r==0);
583 
584     toku_cachetable_close(&ct);
585 }
586 
log16(int n)587 static int log16(int n) {
588     int r = 0;
589     int b = 1;
590     while (b < n) {
591         b *= 16;
592         r += 1;
593     }
594     return r;
595 }
596 
test_multiple_ft_cursor_walk(int n)597 static void test_multiple_ft_cursor_walk(int n) {
598     if (verbose) printf("test_multiple_ft_cursor_walk:%d\n", n);
599 
600     int r;
601     CACHETABLE ct;
602     FT_HANDLE ft;
603     const int cursor_gap = 1000;
604     const int ncursors = n/cursor_gap;
605     FT_CURSOR cursors[ncursors];
606 
607     unlink(fname);
608 
609     int nodesize = 1<<12;
610     int h = log16(n);
611     int cachesize = 2 * h * ncursors * nodesize;
612     toku_cachetable_create(&ct, cachesize, ZERO_LSN, nullptr);
613 
614     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
615     assert(r==0);
616 
617     int c;
618     /* create the cursors */
619     for (c=0; c<ncursors; c++) {
620         r = toku_ft_cursor(ft, &cursors[c], NULL, false, false);
621         assert(r == 0);
622     }
623 
624 
625     /* insert keys 0, 1, 2, ... n-1 */
626     int i;
627     for (i=0; i<n; i++) {
628 	{
629 	    int k = toku_htonl(i);
630 	    int v = i;
631 	    DBT key, val;
632 	    toku_fill_dbt(&key, &k, sizeof k);
633 	    toku_fill_dbt(&val, &v, sizeof v);
634 
635 	    toku_ft_insert(ft, &key, &val, 0);
636 	}
637 
638         /* point cursor i / cursor_gap to the current last key i */
639         if ((i % cursor_gap) == 0) {
640             c = i / cursor_gap;
641 	    struct check_pair pair = {len_ignore, 0, len_ignore, 0, 0};
642             r = toku_ft_cursor_get(cursors[c], NULL, lookup_checkf, &pair, DB_LAST);
643             assert(r == 0);
644 	    assert(pair.call_count==1);
645         }
646     }
647 
648     /* walk the cursors by cursor_gap */
649     for (i=0; i<cursor_gap; i++) {
650         for (c=0; c<ncursors; c++) {
651 	    int vv = c*cursor_gap + i + 1;
652 	    struct check_pair pair = {len_ignore, 0, sizeof vv, &vv, 0};
653             r = toku_ft_cursor_get(cursors[c], NULL, lookup_checkf, &pair, DB_NEXT);
654             if (r == DB_NOTFOUND) {
655                 /* we already consumed 1 previously */
656 		assert(pair.call_count==0);
657                 assert(i == cursor_gap-1);
658             } else {
659                 assert(r == 0);
660 		assert(pair.call_count==1);
661             }
662         }
663     }
664 
665     for (i=0; i<ncursors; i++) {
666         toku_ft_cursor_close(cursors[i]);
667     }
668 
669     r = toku_close_ft_handle_nolsn(ft, 0);
670     assert(r==0);
671 
672     toku_cachetable_close(&ct);
673 }
674 
test_ft_cursor_set(int n,int cursor_op)675 static void test_ft_cursor_set(int n, int cursor_op) {
676     if (verbose) printf("test_ft_cursor_set:%d %d\n", n, cursor_op);
677 
678     int r;
679     CACHETABLE ct;
680     FT_HANDLE ft;
681     FT_CURSOR cursor=0;
682 
683     unlink(fname);
684 
685     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
686 
687     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
688     assert(r==0);
689 
690     int i;
691 
692     /* insert keys 0, 10, 20 .. 10*(n-1) */
693     for (i=0; i<n; i++) {
694         int k = toku_htonl(10*i);
695         int v = 10*i;
696 	DBT key,val;
697         toku_fill_dbt(&key, &k, sizeof k);
698         toku_fill_dbt(&val, &v, sizeof v);
699         toku_ft_insert(ft, &key, &val, 0);
700     }
701 
702     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
703     assert(r==0);
704 
705     /* set cursor to random keys in set { 0, 10, 20, .. 10*(n-1) } */
706     for (i=0; i<n; i++) {
707         int vv;
708 
709         int v = 10*(random() % n);
710         int k = toku_htonl(v);
711 	DBT key;
712         toku_fill_dbt(&key, &k, sizeof k);
713 	struct check_pair pair = {sizeof k, 0, sizeof vv, &v, 0};
714 	if (cursor_op == DB_SET) pair.key = &k; // if it is a set operation, make sure that the result we get is the right one.
715         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, cursor_op);
716         assert(r == 0);
717 	assert(pair.call_count==1);
718     }
719 
720     /* try to set cursor to keys not in the tree, all should fail */
721     for (i=0; i<10*n; i++) {
722         if (i % 10 == 0)
723             continue;
724         int k = toku_htonl(i);
725         DBT key;
726 	toku_fill_dbt(&key, &k, sizeof k);
727 	struct check_pair pair = {0, 0, 0, 0, 0};
728         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, DB_SET);
729         CKERR2(r,DB_NOTFOUND);
730 	assert(pair.call_count==0);
731         assert(key.data == &k); // make sure that no side effect happened on key
732 	assert((unsigned int)k==toku_htonl(i));
733     }
734 
735     toku_ft_cursor_close(cursor);
736 
737     r = toku_close_ft_handle_nolsn(ft, 0);
738     assert(r==0);
739 
740     toku_cachetable_close(&ct);
741 }
742 
test_ft_cursor_set_range(int n)743 static void test_ft_cursor_set_range(int n) {
744     if (verbose) printf("test_ft_cursor_set_range:%d\n", n);
745 
746     int r;
747     CACHETABLE ct;
748     FT_HANDLE ft;
749     FT_CURSOR cursor=0;
750 
751     unlink(fname);
752 
753     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
754 
755     r = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
756     assert(r==0);
757 
758     int i;
759 
760     /* insert keys 0, 10, 20 .. 10*(n-1) */
761     int max_key = 10*(n-1);
762     for (i=0; i<n; i++) {
763         int k = toku_htonl(10*i);
764         int v = 10*i;
765 	DBT key, val;
766         toku_fill_dbt(&key, &k, sizeof k);
767         toku_fill_dbt(&val, &v, sizeof v);
768         toku_ft_insert(ft, &key, &val, 0);
769     }
770 
771     r = toku_ft_cursor(ft, &cursor, NULL, false, false);
772     assert(r==0);
773 
774     /* pick random keys v in 0 <= v < 10*n, the cursor should point
775        to the smallest key in the tree that is >= v */
776     for (i=0; i<n; i++) {
777 
778         int v = random() % (10*n);
779         int k = toku_htonl(v);
780         DBT key;
781 	toku_fill_dbt(&key, &k, sizeof k);
782 	int vv = ((v+9)/10)*10;
783 	struct check_pair pair = {sizeof k, 0, sizeof vv, &vv, 0};
784         r = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, DB_SET_RANGE);
785         if (v > max_key) {
786             /* there is no smallest key if v > the max key */
787             assert(r == DB_NOTFOUND);
788 	    assert(pair.call_count==0);
789 	} else {
790             assert(r == 0);
791 	    assert(pair.call_count==1);
792         }
793     }
794 
795     toku_ft_cursor_close(cursor);
796 
797     r = toku_close_ft_handle_nolsn(ft, 0);
798     assert(r==0);
799 
800     toku_cachetable_close(&ct);
801 }
802 
test_ft_cursor_delete(int n)803 static void test_ft_cursor_delete(int n) {
804     if (verbose) printf("test_ft_cursor_delete:%d\n", n);
805 
806     int error;
807     CACHETABLE ct;
808     FT_HANDLE ft;
809     FT_CURSOR cursor=0;
810 
811     unlink(fname);
812 
813     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
814 
815     error = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, test_ft_cursor_keycompare);
816     assert(error == 0);
817 
818     error = toku_ft_cursor(ft, &cursor, NULL, false, false);
819     assert(error == 0);
820 
821     DBT key, val;
822     int k, v;
823 
824     int i;
825     /* insert keys 0, 1, 2, .. (n-1) */
826     for (i=0; i<n; i++) {
827         k = toku_htonl(i);
828         v = i;
829         toku_fill_dbt(&key, &k, sizeof k);
830         toku_fill_dbt(&val, &v, sizeof v);
831         toku_ft_insert(ft, &key, &val, 0);
832     }
833 
834     /* walk the tree and delete under the cursor */
835     for (;;) {
836 	struct check_pair pair = {len_ignore, 0, len_ignore, 0, 0};
837         error = toku_ft_cursor_get(cursor, &key, lookup_checkf, &pair, DB_NEXT);
838         if (error == DB_NOTFOUND) {
839 	    assert(pair.call_count==0);
840             break;
841 	}
842         assert(error == 0);
843 	assert(pair.call_count==1);
844 
845         error = toku_ft_cursor_delete(cursor, 0, null_txn);
846         assert(error == 0);
847     }
848 
849     error = toku_ft_cursor_delete(cursor, 0, null_txn);
850     assert(error != 0);
851 
852     toku_ft_cursor_close(cursor);
853 
854     error = toku_close_ft_handle_nolsn(ft, 0);
855     assert(error == 0);
856 
857     toku_cachetable_close(&ct);
858 }
859 
860 static int test_ft_cursor_inc = 1000;
861 static int test_ft_cursor_limit = 10000;
862 
test_ft_cursor(void)863 static void test_ft_cursor(void) {
864     int n;
865 
866     test_multiple_ft_cursors(1);
867     test_multiple_ft_cursors(2);
868     test_multiple_ft_cursors(3);
869 
870     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
871         test_ft_cursor_first(n);
872      }
873     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
874         test_ft_cursor_rfirst(n);
875     }
876     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
877         test_ft_cursor_walk(n);
878     }
879     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
880         test_ft_cursor_last(n);
881     }
882     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
883         test_ft_cursor_first_last(n);
884     }
885     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
886         test_ft_cursor_split(n);
887     }
888     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
889         test_ft_cursor_rand(n);
890     }
891     for (n=0; n<test_ft_cursor_limit; n += test_ft_cursor_inc) {
892         test_ft_cursor_rwalk(n);
893     }
894 
895     test_ft_cursor_set(1000, DB_SET);
896     test_ft_cursor_set(10000, DB_SET);
897     test_ft_cursor_set(1000, DB_SET_RANGE);
898     test_ft_cursor_set_range(1000);
899     test_ft_cursor_set_range(10000);
900 
901 
902     test_ft_cursor_delete(1000);
903     test_multiple_ft_cursor_walk(10000);
904     test_multiple_ft_cursor_walk(100000);
905 }
906 
907 
908 int
test_main(int argc,const char * argv[])909 test_main (int argc , const char *argv[]) {
910     default_parse_args(argc, argv);
911     test_ft_cursor();
912     if (verbose) printf("test ok\n");
913     return 0;
914 }
915