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