1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2010 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <stdint.h>
22#include <time.h>
23#if !defined(WIN32) && !defined(_WIN32)
24#include <unistd.h>
25#endif
26
27#include "libforestdb/forestdb.h"
28#include "test.h"
29
30#include "internal_types.h"
31#include "functional_util.h"
32
33
34void iterator_test()
35{
36    TEST_INIT();
37
38    memleak_start();
39
40    int i, r;
41    int n = 10;
42    fdb_file_handle *dbfile;
43    fdb_kvs_handle *db, *kv1;;
44    fdb_doc **doc = alca(fdb_doc*, n);
45    fdb_doc *rdoc = NULL;
46    fdb_status status;
47    fdb_iterator *iterator;
48
49    char keybuf[256], metabuf[256], bodybuf[256], temp[256];
50
51    // remove  all previous iterator_test files
52    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
53    (void)r;
54
55    fdb_config fconfig = fdb_get_default_config();
56    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
57    fconfig.buffercache_size = 0;
58    fconfig.wal_threshold = 1024;
59    fconfig.flags = FDB_OPEN_FLAG_CREATE;
60    fconfig.compaction_threshold = 0;
61
62    // open db
63    fdb_open(&dbfile, "./iterator_test1", &fconfig);
64    fdb_kvs_open_default(dbfile, &db, &kvs_config);
65    status = fdb_set_log_callback(db, logCallbackFunc,
66                                  (void *) "iterator_test");
67    TEST_CHK(status == FDB_RESULT_SUCCESS);
68
69    // Create another KV store..
70    status = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
71    TEST_CHK(status == FDB_RESULT_SUCCESS);
72
73    // insert using 'kv1' instance to ensure it does not interfere
74    for (i=0;i<n;++i){
75        sprintf(keybuf, "kEy%d", i);
76        sprintf(metabuf, "mEta%d", i);
77        sprintf(bodybuf, "bOdy%d", i);
78        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
79            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
80        status = fdb_set(kv1, doc[i]);
81        TEST_CHK(status == FDB_RESULT_SUCCESS);
82        fdb_doc_free(doc[i]);
83    }
84
85    // insert documents of even number
86    for (i=0;i<n;i+=2){
87        sprintf(keybuf, "key%d", i);
88        sprintf(metabuf, "meta%d", i);
89        sprintf(bodybuf, "body%d", i);
90        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
91            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
92        fdb_set(db, doc[i]);
93    }
94    // manually flush WAL & commit
95    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
96
97    // insert documents of odd number
98    for (i=1;i<n;i+=2){
99        sprintf(keybuf, "key%d", i);
100        sprintf(metabuf, "meta%d", i);
101        sprintf(bodybuf, "body%d", i);
102        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
103            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
104        fdb_set(db, doc[i]);
105    }
106    // commit without WAL flush
107    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
108
109    // now even number docs are in hb-trie & odd number docs are in WAL
110
111    // create an iterator for full range
112    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
113
114    // repeat until fail
115    i=0;
116    do {
117        status = fdb_iterator_get(iterator, &rdoc);
118        TEST_CHK(status == FDB_RESULT_SUCCESS);
119
120        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
121        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
122        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
123
124        fdb_doc_free(rdoc);
125        rdoc = NULL;
126        i++;
127    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
128    TEST_CHK(i==10);
129    fdb_iterator_close(iterator);
130
131    // create an iterator.
132    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
133
134    // repeat until fail
135    i=0;
136    do {
137        // retrieve the next doc and get the byte offset of the returned doc
138        status = fdb_iterator_get_metaonly(iterator, &rdoc);
139        TEST_CHK(status == FDB_RESULT_SUCCESS);
140
141        TEST_CHK(rdoc->offset != BLK_NOT_FOUND);
142        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
143        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
144        TEST_CHK(rdoc->body == NULL);
145
146        fdb_doc_free(rdoc);
147        rdoc = NULL;
148        i++;
149    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
150    TEST_CHK(i==10);
151    fdb_iterator_close(iterator);
152
153    // create another iterator starts from doc[3]
154    sprintf(keybuf, "key%d", 3);
155    fdb_iterator_init(db, &iterator, (void*)keybuf, strlen(keybuf), NULL, 0,
156                      FDB_ITR_NONE);
157
158    // repeat until fail
159    i=3;
160    do {
161        status = fdb_iterator_get(iterator, &rdoc);
162        TEST_CHK(status == FDB_RESULT_SUCCESS);
163
164        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
165        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
166        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
167
168        fdb_doc_free(rdoc);
169        rdoc = NULL;
170        i++;
171    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
172    TEST_CHK(i==10);
173    fdb_iterator_close(iterator);
174
175    // create another iterator for the range of doc[4] ~ doc[8]
176    sprintf(keybuf, "key%d", 4);
177    sprintf(temp, "key%d", 8);
178    fdb_iterator_init(db, &iterator, (void*)keybuf, strlen(keybuf),
179        (void*)temp, strlen(temp), FDB_ITR_NONE);
180
181    // repeat until fail
182    i=4;
183    do {
184        status = fdb_iterator_get(iterator, &rdoc);
185        TEST_CHK(status == FDB_RESULT_SUCCESS);
186
187        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
188        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
189        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
190
191        fdb_doc_free(rdoc);
192        rdoc = NULL;
193        i++;
194    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
195    TEST_CHK(i==9);
196    fdb_iterator_close(iterator);
197
198    // create another iterator for the range of doc[5] ~ doc[7]
199    fdb_iterator_init(db, &iterator, (void*)keybuf, strlen(keybuf),
200        (void*)temp, strlen(temp), FDB_ITR_SKIP_MIN_KEY | FDB_ITR_SKIP_MAX_KEY);
201
202    // repeat until fail
203    i=5;
204    do {
205        status = fdb_iterator_get(iterator, &rdoc);
206        TEST_CHK(status == FDB_RESULT_SUCCESS);
207
208        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
209        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
210        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
211
212        fdb_doc_free(rdoc);
213        rdoc = NULL;
214        i++;
215    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
216    TEST_CHK(i==8);
217    fdb_iterator_close(iterator);
218
219    // remove document #8 and #9
220    fdb_doc_create(&rdoc, doc[8]->key, doc[8]->keylen, doc[8]->meta,
221                   doc[8]->metalen, NULL, 0);
222    status = fdb_del(db, rdoc);
223    TEST_CHK(status == FDB_RESULT_SUCCESS);
224    fdb_doc_free(rdoc);
225    rdoc = NULL;
226    fdb_doc_create(&rdoc, doc[9]->key, doc[9]->keylen, doc[9]->meta,
227                   doc[9]->metalen, NULL, 0);
228    status = fdb_del(db, rdoc);
229    TEST_CHK(status == FDB_RESULT_SUCCESS);
230    fdb_doc_free(rdoc);
231    rdoc = NULL;
232    // commit
233    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
234
235    // create an iterator for full range
236    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
237    // repeat until fail
238    i=0;
239    do {
240        status = fdb_iterator_get(iterator, &rdoc);
241        TEST_CHK(status == FDB_RESULT_SUCCESS);
242
243        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
244        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
245        if (i < 8) {
246            TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
247        } else {
248            TEST_CHK(rdoc->deleted == true);
249        }
250
251        fdb_doc_free(rdoc);
252        rdoc = NULL;
253        i++;
254    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
255    TEST_CHK(i==10);
256    fdb_iterator_close(iterator);
257
258    // create an iterator for full range, but no deletes.
259    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NO_DELETES);
260    // repeat until fail
261    i=0;
262    do {
263        status = fdb_iterator_get(iterator, &rdoc);
264        TEST_CHK(status == FDB_RESULT_SUCCESS);
265
266        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
267        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
268        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
269
270        fdb_doc_free(rdoc);
271        rdoc = NULL;
272        i++;
273    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
274    TEST_CHK(i==8);
275    fdb_iterator_close(iterator);
276
277    // create an iterator for range of doc[4] ~ doc[8], but no deletes.
278    sprintf(keybuf, "key%d", 4);
279    sprintf(temp, "key%d", 8);
280    fdb_iterator_init(db, &iterator, keybuf, strlen(keybuf), temp, strlen(temp),
281                      FDB_ITR_NO_DELETES);
282    // repeat until fail
283    i=4;
284    do {
285        status = fdb_iterator_get(iterator, &rdoc);
286        TEST_CHK(status == FDB_RESULT_SUCCESS);
287
288        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
289        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
290        TEST_CHK(rdoc->deleted == false);
291
292        fdb_doc_free(rdoc);
293        rdoc = NULL;
294        i++;
295    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
296    TEST_CHK(i==8);
297    fdb_iterator_close(iterator);
298
299    // close kvs1 instance
300    fdb_kvs_close(kv1);
301    // close db file
302    fdb_kvs_close(db);
303    fdb_close(dbfile);
304
305    // free all documents
306    for (i=0;i<n;++i){
307        fdb_doc_free(doc[i]);
308    }
309
310    // free all resources
311    fdb_shutdown();
312
313    memleak_end();
314
315    TEST_RESULT("iterator test");
316}
317
318void iterator_with_concurrent_updates_test()
319{
320    // unit test for MB-12287
321    TEST_INIT();
322    memleak_start();
323
324    int i, n=10;
325    int r;
326    fdb_file_handle *dbfile;
327    fdb_kvs_handle *db1, *db2, *db3;
328    fdb_iterator *itr;
329    fdb_config fconfig;
330    fdb_kvs_config kvs_config;
331    fdb_doc **doc = alca(fdb_doc*, n);
332    fdb_doc *rdoc = NULL;
333    fdb_status status;
334    char keybuf[256], bodybuf[256];
335
336    // remove previous iterator_test files
337    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
338    (void)r;
339
340    // open db1, db2, db3 on the same file
341    fconfig = fdb_get_default_config();
342    kvs_config = fdb_get_default_kvs_config();
343    fdb_open(&dbfile, "./iterator_test1", &fconfig);
344
345    fdb_kvs_open_default(dbfile, &db1, &kvs_config);
346    status = fdb_set_log_callback(db1, logCallbackFunc,
347                                  (void *) "iterator_concurrent_update_test");
348    TEST_CHK(status == FDB_RESULT_SUCCESS);
349
350    fdb_kvs_open_default(dbfile, &db2, &kvs_config);
351    status = fdb_set_log_callback(db2, logCallbackFunc,
352                                  (void *) "iterator_concurrent_update_test");
353    TEST_CHK(status == FDB_RESULT_SUCCESS);
354
355    fdb_kvs_open_default(dbfile, &db3, &kvs_config);
356    status = fdb_set_log_callback(db3, logCallbackFunc,
357                                  (void *) "iterator_concurrent_update_test");
358    TEST_CHK(status == FDB_RESULT_SUCCESS);
359
360    // insert docs using db1
361    for (i=0;i<10;++i){
362        sprintf(keybuf, "key%d", i);
363        sprintf(bodybuf, "body%d", i);
364        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf), NULL, 0,
365                       (void*)bodybuf, strlen(bodybuf));
366        fdb_set(db1, doc[i]);
367    }
368    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
369
370    // create an iterator using db2
371    fdb_iterator_init(db2, &itr, NULL, 0, NULL, 0, FDB_ITR_NONE);
372    r = 0;
373    do {
374        status = fdb_iterator_get(itr, &rdoc);
375        TEST_CHK(status == FDB_RESULT_SUCCESS);
376        TEST_CMP(rdoc->key, doc[r]->key, rdoc->keylen);
377        TEST_CMP(rdoc->body, doc[r]->body, rdoc->bodylen);
378        r++;
379        fdb_doc_free(rdoc);
380        rdoc = NULL;
381    } while (fdb_iterator_next(itr) == FDB_RESULT_SUCCESS);
382    fdb_iterator_close(itr);
383    TEST_CHK(r == n);
384
385    // same for sequence number
386    fdb_iterator_sequence_init(db3, &itr, 0, 0, FDB_ITR_NONE);
387    r = 0;
388    do {
389        status = fdb_iterator_get(itr, &rdoc);
390        TEST_CHK(status == FDB_RESULT_SUCCESS);
391        r++;
392        TEST_CHK(rdoc->seqnum == (fdb_seqnum_t)r);
393        fdb_doc_free(rdoc);
394        rdoc = NULL;
395    } while (fdb_iterator_next(itr) == FDB_RESULT_SUCCESS);
396    fdb_iterator_close(itr);
397    TEST_CHK(r == n);
398
399    fdb_close(dbfile);
400
401    // free all documents
402    for (i=0;i<n;++i){
403        fdb_doc_free(doc[i]);
404    }
405
406    fdb_shutdown();
407
408    memleak_end();
409    TEST_RESULT("iterator with concurrent updates test");
410}
411
412void iterator_compact_uncommitted_db()
413{
414    TEST_INIT();
415    memleak_start();
416
417    int i, r;
418    int n = 10;
419    char keybuf[256], bodybuf[256];
420    fdb_file_handle *dbfile;
421    fdb_kvs_handle *db;
422    fdb_status status;
423    fdb_iterator *it;
424    fdb_config fconfig = fdb_get_default_config();
425    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
426    fconfig.wal_threshold = 1024;
427    fconfig.flags = FDB_OPEN_FLAG_CREATE;
428
429    // remove previous iterator_test files
430    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
431    (void)r;
432
433    // open db
434    fdb_open(&dbfile, "./iterator_test1", &fconfig);
435    fdb_kvs_open(dbfile, &db, "db1", &kvs_config);
436
437
438    // set docs
439    for (i=0;i<n;++i){
440        sprintf(keybuf, "key%d", i);
441        sprintf(bodybuf, "body%d", i);
442        fdb_set_kv(db, keybuf, strlen(keybuf),
443                bodybuf, strlen(bodybuf));
444    }
445
446    // count number of iteratable docs
447    status = fdb_iterator_sequence_init(db, &it, 0, 0, FDB_ITR_NONE);
448    TEST_CHK(status == FDB_RESULT_SUCCESS);
449    i=0;
450    do { ++i; }
451    while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
452    fdb_iterator_close(it);
453    TEST_CHK(i == n);
454
455    // compact
456    fdb_compact(dbfile, NULL);
457
458    // set again
459    for (i=0;i<n;++i){
460        sprintf(keybuf, "key%d", i);
461        sprintf(bodybuf, "body%d", i);
462        fdb_set_kv(db, keybuf, strlen(keybuf),
463                bodybuf, strlen(bodybuf));
464    }
465
466    // count number of iteratable docs
467    status = fdb_iterator_sequence_init(db, &it, 0, 0, FDB_ITR_NONE);
468    TEST_CHK(status == FDB_RESULT_SUCCESS);
469    i=0;
470    do { ++i; }
471    while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
472    fdb_iterator_close(it);
473    TEST_CHK(i == n);
474
475
476    fdb_kvs_close(db);
477    fdb_close(dbfile);
478    fdb_shutdown();
479
480    memleak_end();
481    TEST_RESULT("iterator compact uncommitted db");
482}
483
484void iterator_seek_test()
485{
486    TEST_INIT();
487
488    memleak_start();
489
490    int i, r;
491    int n = 10;
492    fdb_file_handle *dbfile;
493    fdb_kvs_handle *db, *kv1;
494    fdb_doc **doc = alca(fdb_doc*, n);
495    fdb_doc *rdoc = NULL;
496    fdb_status status;
497    fdb_iterator *iterator;
498
499    char keybuf[256], metabuf[256], bodybuf[256];
500
501    // remove previous iterator_test files
502    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
503    (void)r;
504
505    fdb_config fconfig = fdb_get_default_config();
506    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
507    fconfig.buffercache_size = 0;
508    fconfig.wal_threshold = 1024;
509    fconfig.flags = FDB_OPEN_FLAG_CREATE;
510    fconfig.compaction_threshold = 0;
511
512    // open db
513    fdb_open(&dbfile, "./iterator_test1", &fconfig);
514    fdb_kvs_open_default(dbfile, &db, &kvs_config);
515    status = fdb_set_log_callback(db, logCallbackFunc,
516                                  (void *) "iterator_seek_test");
517    TEST_CHK(status == FDB_RESULT_SUCCESS);
518
519    // Create another KV store..
520    status = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
521    TEST_CHK(status == FDB_RESULT_SUCCESS);
522
523    // insert using 'kv1' instance to ensure it does not interfere
524    for (i=0;i<n;++i){
525        sprintf(keybuf, "kEy%d", i);
526        sprintf(metabuf, "mEta%d", i);
527        sprintf(bodybuf, "bOdy%d", i);
528        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
529            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
530        status = fdb_set(kv1, doc[i]);
531        TEST_CHK(status == FDB_RESULT_SUCCESS);
532        fdb_doc_free(doc[i]);
533    }
534
535    // insert documents of odd number into the main (default) KV store handle
536    for (i=1;i<n;i+=2){
537        sprintf(keybuf, "key%d", i);
538        sprintf(metabuf, "meta%d", i);
539        sprintf(bodybuf, "body%d", i);
540        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
541            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
542        fdb_set(db, doc[i]);
543    }
544    // manually flush WAL & commit
545    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
546
547    // insert documents of even number
548    for (i=0;i<n;i+=2){
549        sprintf(keybuf, "key%d", i);
550        sprintf(metabuf, "meta%d", i);
551        sprintf(bodybuf, "body%d", i);
552        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
553            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
554        fdb_set(db, doc[i]);
555    }
556    // commit without WAL flush
557    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
558
559    // now odd number docs are in hb-trie & even number docs are in WAL
560
561    // create an iterator for full range
562    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
563
564    // seek current iterator to inside the WAL's avl tree..
565    status = fdb_iterator_get(iterator, &rdoc);
566    TEST_CHK(status == FDB_RESULT_SUCCESS);
567
568    TEST_CMP(rdoc->key, doc[0]->key, rdoc->keylen);
569    TEST_CMP(rdoc->meta, doc[0]->meta, rdoc->metalen);
570    TEST_CMP(rdoc->body, doc[0]->body, rdoc->bodylen);
571    fdb_doc_free(rdoc);
572    rdoc = NULL;
573
574    // seek forward to 2nd key ..
575    i=2;
576    status = fdb_iterator_seek(iterator, doc[i]->key, strlen(keybuf), 0);
577    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
578    status = fdb_iterator_get(iterator, &rdoc);
579    TEST_CHK(status == FDB_RESULT_SUCCESS);
580
581    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
582    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
583    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
584    fdb_doc_free(rdoc);
585    rdoc = NULL;
586
587    // iterator should be able to proceed forward
588    status = fdb_iterator_next(iterator);
589    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
590    status = fdb_iterator_get(iterator, &rdoc);
591    TEST_CHK(status == FDB_RESULT_SUCCESS);
592
593    i++;
594    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
595    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
596    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
597    fdb_doc_free(rdoc);
598    rdoc = NULL;
599
600    // seek forward to the last key.
601    status = fdb_iterator_seek(iterator, doc[n-1]->key, strlen(keybuf), 0);
602    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
603    status = fdb_iterator_get(iterator, &rdoc);
604    TEST_CHK(status == FDB_RESULT_SUCCESS);
605
606    TEST_CMP(rdoc->key, doc[n-1]->key, rdoc->keylen);
607    TEST_CMP(rdoc->meta, doc[n-1]->meta, rdoc->metalen);
608    TEST_CMP(rdoc->body, doc[n-1]->body, rdoc->bodylen);
609    fdb_doc_free(rdoc);
610    rdoc = NULL;
611
612    // seek backward to start key ..
613    i = 0;
614    status = fdb_iterator_seek(iterator, doc[i]->key, strlen(keybuf), 0);
615    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
616    status = fdb_iterator_get(iterator, &rdoc);
617    TEST_CHK(status == FDB_RESULT_SUCCESS);
618
619    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
620    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
621    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
622    fdb_doc_free(rdoc);
623    rdoc = NULL;
624
625    // seek forward to key2 ..
626    status = fdb_iterator_seek(iterator, doc[2]->key, strlen(keybuf), 0);
627    TEST_CHK(status == FDB_RESULT_SUCCESS);
628
629    i=2;
630    do {
631        status = fdb_iterator_get(iterator, &rdoc);
632        TEST_CHK(status == FDB_RESULT_SUCCESS);
633
634        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
635        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
636        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
637
638        fdb_doc_free(rdoc);
639        rdoc = NULL;
640        i++;
641    } while(fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
642    TEST_CHK(i==10);
643
644    // Seek backward again to a key in the trie...
645    status = fdb_iterator_seek(iterator, doc[3]->key, strlen(keybuf), 0);
646    TEST_CHK(status == FDB_RESULT_SUCCESS);
647
648    i=3;
649    do {
650        status = fdb_iterator_get(iterator, &rdoc);
651        TEST_CHK(status == FDB_RESULT_SUCCESS);
652
653        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
654        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
655        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
656
657        fdb_doc_free(rdoc);
658        rdoc = NULL;
659        i++;
660    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
661    TEST_CHK(i==10);
662
663    fdb_iterator_close(iterator);
664
665    // Test fdb_iterator_seek_to_max with key range
666    // create an iterator for range of doc[4] ~ doc[8]
667    sprintf(keybuf, "key%d", 4); // reuse buffer for start key
668    sprintf(metabuf, "key%d", 8); // reuse buffer for end_key
669    status = fdb_iterator_init(db, &iterator, keybuf, strlen(keybuf),
670                      metabuf, strlen(metabuf),
671                      FDB_ITR_NO_DELETES);
672    TEST_CHK(status == FDB_RESULT_SUCCESS);
673    i = 8;
674    status = fdb_iterator_seek_to_max(iterator);
675    TEST_CHK(status == FDB_RESULT_SUCCESS);
676    status = fdb_iterator_get(iterator, &rdoc);
677    TEST_CHK(status == FDB_RESULT_SUCCESS);
678
679    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
680    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
681    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
682    fdb_doc_free(rdoc);
683    rdoc = NULL;
684
685    // test fdb_iterator_seek_to_min
686    i = 4;
687    status = fdb_iterator_seek_to_min(iterator);
688    TEST_CHK(status == FDB_RESULT_SUCCESS);
689    status = fdb_iterator_get(iterator, &rdoc);
690    TEST_CHK(status == FDB_RESULT_SUCCESS);
691
692    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
693    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
694    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
695    fdb_doc_free(rdoc);
696    rdoc = NULL;
697
698    status = fdb_iterator_close(iterator);
699    TEST_CHK(status == FDB_RESULT_SUCCESS);
700
701    // Test fdb_iterator_seek_to_max over full range
702    status = fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
703    TEST_CHK(status == FDB_RESULT_SUCCESS);
704
705    i = n - 1;
706    status = fdb_iterator_seek_to_max(iterator);
707    TEST_CHK(status == FDB_RESULT_SUCCESS);
708    status = fdb_iterator_get(iterator, &rdoc);
709    TEST_CHK(status == FDB_RESULT_SUCCESS);
710
711    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
712    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
713    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
714    fdb_doc_free(rdoc);
715    rdoc = NULL;
716
717    // test fdb_iterator_seek_to_min
718    i = 0;
719    status = fdb_iterator_seek_to_min(iterator);
720    TEST_CHK(status == FDB_RESULT_SUCCESS);
721    status = fdb_iterator_get(iterator, &rdoc);
722    TEST_CHK(status == FDB_RESULT_SUCCESS);
723
724    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
725    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
726    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
727    fdb_doc_free(rdoc);
728    rdoc = NULL;
729
730    // seek to max using a non-existent FFFF key
731    if (status == FDB_RESULT_SUCCESS) {
732        uint8_t *big_seek_key = alca(uint8_t, FDB_MAX_KEYLEN);
733        memset(big_seek_key, 0xff, FDB_MAX_KEYLEN);
734        status = fdb_iterator_seek(iterator, big_seek_key, FDB_MAX_KEYLEN,
735                                   FDB_ITR_SEEK_LOWER);
736        TEST_CHK(status == FDB_RESULT_SUCCESS);
737        i = n - 1;
738        status = fdb_iterator_get(iterator, &rdoc);
739        TEST_CHK(status == FDB_RESULT_SUCCESS);
740
741        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
742        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
743        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
744        fdb_doc_free(rdoc);
745        rdoc = NULL;
746    }
747
748    status = fdb_iterator_close(iterator);
749    TEST_CHK(status == FDB_RESULT_SUCCESS);
750
751    // delete documents of even number so WAL only has deleted docs
752    for (i=0;i<n;i+=2){
753        status = fdb_del(db, doc[i]);
754        TEST_CHK(status == FDB_RESULT_SUCCESS);
755    }
756    // commit without WAL flush
757    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
758
759    // create an iterator for full range
760    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
761
762    // seek forward to 2nd key ..
763    rdoc = NULL;
764    i=2;
765    status = fdb_iterator_seek(iterator, doc[i]->key, strlen(keybuf), 0);
766    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
767    status = fdb_iterator_get(iterator, &rdoc);
768    TEST_CHK(status == FDB_RESULT_SUCCESS);
769
770    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
771    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
772    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
773    fdb_doc_free(rdoc);
774    rdoc = NULL;
775
776    status = fdb_iterator_close(iterator);
777    TEST_CHK(status == FDB_RESULT_SUCCESS);
778
779    // close the kvs kv1
780    fdb_kvs_close(kv1);
781    // close db file
782    fdb_kvs_close(db);
783    fdb_close(dbfile);
784
785    // free all documents
786    for (i=0;i<n;++i){
787        fdb_doc_free(doc[i]);
788    }
789
790    // free all resources
791    fdb_shutdown();
792
793    memleak_end();
794
795    TEST_RESULT("iterator seek test");
796}
797
798void iterator_complete_test(int insert_opt, int delete_opt)
799{
800    TEST_INIT();
801
802    int n = 30;
803    int i, r, c;
804    int *doc_status = alca(int, n); // 0:HB+trie, 1:WAL, 2:deleted
805    char cmd[256];
806    char key[256], value[256];
807    char keystr[] = "key%06d";
808    char keystr_mid[] = "key%06d+";
809    char valuestr[] = "value%08d";
810    char valuestr2[] = "value%08d(WAL)";
811    fdb_file_handle *dbfile;
812    fdb_kvs_handle *db, *db_prev, *db_next;
813    fdb_config config;
814    fdb_kvs_config kvs_config;
815    fdb_doc *doc = NULL;
816    fdb_iterator *fit;
817    fdb_iterator_opt_t itr_opt;
818    fdb_status s;
819    uint64_t mask = 0x11111111111; //0x11111111111
820
821    sprintf(cmd, SHELL_DEL " iterator_test*");
822    r = system(cmd);
823    (void)r;
824
825    memleak_start();
826
827    config = fdb_get_default_config();
828    kvs_config = fdb_get_default_kvs_config();
829    s = fdb_open(&dbfile, "./iterator_test", &config);
830    TEST_CHK(s == FDB_RESULT_SUCCESS);
831
832    s = fdb_kvs_open(dbfile, &db_prev, "prev KVS", &kvs_config);
833    TEST_CHK(s == FDB_RESULT_SUCCESS);
834    s = fdb_kvs_open(dbfile, &db, "cur KVS", &kvs_config);
835    TEST_CHK(s == FDB_RESULT_SUCCESS);
836    s = fdb_kvs_open(dbfile, &db_next, "next KVS", &kvs_config);
837    TEST_CHK(s == FDB_RESULT_SUCCESS);
838
839    sprintf(key, "prev_key");
840    sprintf(value, "prev_value");
841    s = fdb_set_kv(db_prev, key, strlen(key)+1, value, strlen(value)+1);
842    TEST_CHK(s == FDB_RESULT_SUCCESS);
843
844    sprintf(key, "next_key");
845    sprintf(value, "next_value");
846    s = fdb_set_kv(db_next, key, strlen(key)+1, value, strlen(value)+1);
847    TEST_CHK(s == FDB_RESULT_SUCCESS);
848
849    sprintf(key, "next_key2");
850    sprintf(value, "next_value2");
851    s = fdb_set_kv(db_next, key, strlen(key)+1, value, strlen(value)+1);
852    TEST_CHK(s == FDB_RESULT_SUCCESS);
853
854    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
855    TEST_CHK(s == FDB_RESULT_SUCCESS);
856
857    if (insert_opt == 0) {
858        // HB+trie contains all keys
859        // WAL contains even number keys only
860        for (i=0;i<n;++i){
861            sprintf(key, keystr, (int)i);
862            sprintf(value, valuestr, (int)i);
863            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
864            TEST_CHK(s == FDB_RESULT_SUCCESS);
865            doc_status[i] = 0;
866        }
867        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
868        TEST_CHK(s == FDB_RESULT_SUCCESS);
869        if (delete_opt) {
870            // remove doc #15
871            i = 15;
872            sprintf(key, keystr, (int)i);
873            s = fdb_del_kv(db, key, strlen(key)+1);
874            TEST_CHK(s == FDB_RESULT_SUCCESS);
875            s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
876            TEST_CHK(s == FDB_RESULT_SUCCESS);
877            doc_status[i] = 2;
878        }
879
880        for (i=0;i<n;i+=2){
881            sprintf(key, keystr, (int)i);
882            sprintf(value, valuestr2, (int)i);
883            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
884            TEST_CHK(s == FDB_RESULT_SUCCESS);
885            doc_status[i] = 1;
886        }
887        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
888        TEST_CHK(s == FDB_RESULT_SUCCESS);
889    } else if (insert_opt == 1) {
890        // HB+trie contains all keys
891        // WAL contains odd number keys only
892        for (i=0;i<n;++i){
893            sprintf(key, keystr, (int)i);
894            sprintf(value, valuestr, (int)i);
895            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
896            TEST_CHK(s == FDB_RESULT_SUCCESS);
897            doc_status[i] = 0;
898        }
899        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
900        TEST_CHK(s == FDB_RESULT_SUCCESS);
901        for (i=1;i<n;i+=2){
902            sprintf(key, keystr, (int)i);
903            sprintf(value, valuestr2, (int)i);
904            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
905            TEST_CHK(s == FDB_RESULT_SUCCESS);
906            doc_status[i] = 1;
907        }
908        if (delete_opt) {
909            // remove doc #15
910            i = 15;
911            sprintf(key, keystr, (int)i);
912            s = fdb_del_kv(db, key, strlen(key)+1);
913            TEST_CHK(s == FDB_RESULT_SUCCESS);
914            doc_status[i] = 2;
915        }
916        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
917        TEST_CHK(s == FDB_RESULT_SUCCESS);
918    } else if (insert_opt == 2) {
919        // HB+trie contains odd number keys
920        // WAL contains even number keys
921        for (i=1;i<n;i+=2){
922            sprintf(key, keystr, (int)i);
923            sprintf(value, valuestr, (int)i);
924            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
925            TEST_CHK(s == FDB_RESULT_SUCCESS);
926            doc_status[i] = 0;
927        }
928        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
929        TEST_CHK(s == FDB_RESULT_SUCCESS);
930        if (delete_opt) {
931            // remove doc #15
932            i = 15;
933            sprintf(key, keystr, (int)i);
934            s = fdb_del_kv(db, key, strlen(key)+1);
935            TEST_CHK(s == FDB_RESULT_SUCCESS);
936            s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
937            TEST_CHK(s == FDB_RESULT_SUCCESS);
938            doc_status[i] = 2;
939        }
940
941        for (i=0;i<n;i+=2){
942            sprintf(key, keystr, (int)i);
943            sprintf(value, valuestr2, (int)i);
944            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
945            TEST_CHK(s == FDB_RESULT_SUCCESS);
946            doc_status[i] = 1;
947        }
948        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
949        TEST_CHK(s == FDB_RESULT_SUCCESS);
950    } else if (insert_opt == 3) {
951        // HB+trie contains even number keys
952        // WAL contains odd number keys
953        for (i=0;i<n;i+=2){
954            sprintf(key, keystr, (int)i);
955            sprintf(value, valuestr, (int)i);
956            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
957            TEST_CHK(s == FDB_RESULT_SUCCESS);
958            doc_status[i] = 0;
959        }
960        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
961        TEST_CHK(s == FDB_RESULT_SUCCESS);
962        for (i=1;i<n;i+=2){
963            sprintf(key, keystr, (int)i);
964            sprintf(value, valuestr2, (int)i);
965            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
966            TEST_CHK(s == FDB_RESULT_SUCCESS);
967            doc_status[i] = 1;
968        }
969        if (delete_opt) {
970            // remove doc #15
971            i = 15;
972            sprintf(key, keystr, (int)i);
973            s = fdb_del_kv(db, key, strlen(key)+1);
974            TEST_CHK(s == FDB_RESULT_SUCCESS);
975            doc_status[i] = 2;
976        }
977        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
978        TEST_CHK(s == FDB_RESULT_SUCCESS);
979    } else if (insert_opt == 4) {
980        // HB+trie contains all keys
981        // WAL is empty
982        for (i=0;i<n;i+=1){
983            sprintf(key, keystr, (int)i);
984            sprintf(value, valuestr, (int)i);
985            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
986            TEST_CHK(s == FDB_RESULT_SUCCESS);
987            doc_status[i] = 0;
988        }
989        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
990        TEST_CHK(s == FDB_RESULT_SUCCESS);
991        if (delete_opt) {
992            // remove doc #15
993            i = 15;
994            sprintf(key, keystr, (int)i);
995            s = fdb_del_kv(db, key, strlen(key)+1);
996            TEST_CHK(s == FDB_RESULT_SUCCESS);
997            doc_status[i] = 2;
998        }
999        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1000        TEST_CHK(s == FDB_RESULT_SUCCESS);
1001    } else if (insert_opt == 5) {
1002        // HB+trie is empty
1003        // WAL contains all keys
1004        for (i=0;i<n;i+=1){
1005            sprintf(key, keystr, (int)i);
1006            sprintf(value, valuestr, (int)i);
1007            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
1008            TEST_CHK(s == FDB_RESULT_SUCCESS);
1009            doc_status[i] = 0;
1010        }
1011        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1012        TEST_CHK(s == FDB_RESULT_SUCCESS);
1013        if (delete_opt) {
1014            // remove doc #15
1015            i = 15;
1016            sprintf(key, keystr, (int)i);
1017            s = fdb_del_kv(db, key, strlen(key)+1);
1018            TEST_CHK(s == FDB_RESULT_SUCCESS);
1019            doc_status[i] = 2;
1020        }
1021        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1022        TEST_CHK(s == FDB_RESULT_SUCCESS);
1023    } else { // if (insert_opt == 6) {
1024        // Both HB+trie and WAL contains all keys
1025        for (i=0;i<n;++i){
1026            sprintf(key, keystr, (int)i);
1027            sprintf(value, valuestr, (int)i);
1028            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
1029            TEST_CHK(s == FDB_RESULT_SUCCESS);
1030            doc_status[i] = 0;
1031        }
1032        s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1033        TEST_CHK(s == FDB_RESULT_SUCCESS);
1034        for (i=0;i<n;i++){
1035            sprintf(key, keystr, (int)i);
1036            sprintf(value, valuestr2, (int)i);
1037            s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
1038            TEST_CHK(s == FDB_RESULT_SUCCESS);
1039            doc_status[i] = 1;
1040        }
1041        if (delete_opt) {
1042            // remove doc #15
1043            i = 15;
1044            sprintf(key, keystr, (int)i);
1045            s = fdb_del_kv(db, key, strlen(key)+1);
1046            TEST_CHK(s == FDB_RESULT_SUCCESS);
1047            doc_status[i] = 2;
1048        }
1049        s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1050        TEST_CHK(s == FDB_RESULT_SUCCESS);
1051    }
1052
1053    if (delete_opt) {
1054        itr_opt = FDB_ITR_NO_DELETES;
1055    } else {
1056        itr_opt = FDB_ITR_NONE;
1057    }
1058
1059    s = fdb_iterator_init(db, &fit, NULL, 0, NULL, 0, itr_opt);
1060    TEST_CHK(s == FDB_RESULT_SUCCESS);
1061    if (mask & 0x1) {
1062        c = 0;
1063        do {
1064            s = fdb_iterator_get(fit, &doc);
1065            if (s != FDB_RESULT_SUCCESS) {
1066                if (s == FDB_RESULT_KEY_NOT_FOUND) {
1067                    continue;
1068                } else {
1069                    break;
1070                }
1071            }
1072            c += ((doc_status[c] == 2)?(1):(0));
1073            sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1074            TEST_CMP(doc->body, value, doc->bodylen);
1075            fdb_doc_free(doc);
1076            doc = NULL;
1077            c++;
1078        } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1079        TEST_CHK(c == n);
1080        while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL) {
1081            c--;
1082            s = fdb_iterator_get(fit, &doc);
1083            if (s != FDB_RESULT_SUCCESS) {
1084                if (s == FDB_RESULT_KEY_NOT_FOUND) {
1085                    continue;
1086                } else {
1087                    break;
1088                }
1089            }
1090            c -= ((doc_status[c] == 2)?(1):(0));
1091            sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1092            TEST_CMP(doc->body, value, doc->bodylen);
1093            fdb_doc_free(doc);
1094            doc = NULL;
1095        }
1096        TEST_CHK(c == 0);
1097    }
1098
1099    if (mask & 0x10) {
1100        for (i=0;i<n;++i){
1101            sprintf(key, keystr, (int)i);
1102            s = fdb_iterator_seek(fit, key, strlen(key)+1, 0x0);
1103            TEST_CHK(s == FDB_RESULT_SUCCESS);
1104            c = i;
1105            if (doc_status[c] == 2) {
1106                c++; // higher mode
1107            }
1108            do {
1109                s = fdb_iterator_get(fit, &doc);
1110                if (s != FDB_RESULT_SUCCESS) break;
1111                sprintf(key, keystr, (int)c);
1112                c += ((doc_status[c] == 2)?(1):(0));
1113                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1114                TEST_CMP(doc->body, value, doc->bodylen);
1115                fdb_doc_free(doc);
1116                doc = NULL;
1117                c++;
1118            } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1119            TEST_CHK(c == n);
1120        }
1121    }
1122
1123    if (mask & 0x100) {
1124        for (i=0;i<n;++i){
1125            sprintf(key, keystr, (int)i);
1126            s = fdb_iterator_seek(fit, key, strlen(key)+1, 0x0);
1127            TEST_CHK(s == FDB_RESULT_SUCCESS);
1128            c = i;
1129            if (doc_status[c] == 2) {
1130                c++; // higher mode
1131            }
1132            do {
1133                s = fdb_iterator_get(fit, &doc);
1134                if (s != FDB_RESULT_SUCCESS) break;
1135                sprintf(key, keystr, (int)c);
1136                c -= ((doc_status[c] == 2)?(1):(0));
1137                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1138                TEST_CMP(doc->body, value, doc->bodylen);
1139                fdb_doc_free(doc);
1140                doc = NULL;
1141                c--;
1142            } while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL);
1143            TEST_CHK(c == -1);
1144        }
1145    }
1146
1147    if (mask & 0x1000) {
1148        for (i=0;i<n;++i){
1149            sprintf(key, keystr, (int)i);
1150            s = fdb_iterator_seek(fit, key, strlen(key)+1, FDB_ITR_SEEK_LOWER);
1151            TEST_CHK(s == FDB_RESULT_SUCCESS);
1152            c = i;
1153            if (doc_status[c] == 2) {
1154                c--; // lower mode
1155            }
1156            do {
1157                s = fdb_iterator_get(fit, &doc);
1158                if (s != FDB_RESULT_SUCCESS) break;
1159                sprintf(key, keystr, (int)c);
1160                c += ((doc_status[c] == 2)?(1):(0));
1161                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1162                TEST_CMP(doc->body, value, doc->bodylen);
1163                fdb_doc_free(doc);
1164                doc = NULL;
1165                c++;
1166            } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1167            TEST_CHK(c == n);
1168        }
1169    }
1170
1171    if (mask & 0x10000) {
1172        for (i=0;i<n;++i){
1173            sprintf(key, keystr, (int)i);
1174            s = fdb_iterator_seek(fit, key, strlen(key)+1, FDB_ITR_SEEK_LOWER);
1175            TEST_CHK(s == FDB_RESULT_SUCCESS);
1176            c = i;
1177            if (doc_status[c] == 2) {
1178                c--; // lower mode
1179            }
1180            do {
1181                s = fdb_iterator_get(fit, &doc);
1182                if (s != FDB_RESULT_SUCCESS) break;
1183                sprintf(key, keystr, (int)c);
1184                c -= ((doc_status[c] == 2)?(1):(0));
1185                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1186                TEST_CMP(doc->body, value, doc->bodylen);
1187                fdb_doc_free(doc);
1188                doc = NULL;
1189                c--;
1190            } while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL);
1191            TEST_CHK(c == -1);
1192        }
1193    }
1194
1195    if (mask & 0x100000) {
1196        for (i=0;i<n;++i){
1197            sprintf(key, keystr_mid, (int)i);
1198            s = fdb_iterator_seek(fit, key, strlen(key)+1, 0x0);
1199            (void)s;
1200            c = i+1;
1201            if (doc_status[c] == 2) {
1202                c++; // higher mode
1203            }
1204            do {
1205                s = fdb_iterator_get(fit, &doc);
1206                if (s != FDB_RESULT_SUCCESS) break;
1207                sprintf(key, keystr_mid, (int)c);
1208                c += ((doc_status[c] == 2)?(1):(0));
1209                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1210                TEST_CMP(doc->body, value, doc->bodylen);
1211                fdb_doc_free(doc);
1212                doc = NULL;
1213                c++;
1214            } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1215            TEST_CHK(c == n);
1216        }
1217    }
1218
1219    if (mask & 0x1000000) {
1220        for (i=0;i<n;++i){
1221            sprintf(key, keystr_mid, (int)i);
1222            s = fdb_iterator_seek(fit, key, strlen(key)+1, 0x0);
1223            (void)s;
1224            c = i+1;
1225            if (doc_status[c] == 2) {
1226                c++; // higher mode
1227            }
1228            do {
1229                s = fdb_iterator_get(fit, &doc);
1230                if (s != FDB_RESULT_SUCCESS) break;
1231                sprintf(key, keystr_mid, (int)c);
1232                c -= ((doc_status[c] == 2)?(1):(0));
1233                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1234                TEST_CMP(doc->body, value, doc->bodylen);
1235                fdb_doc_free(doc);
1236                doc = NULL;
1237                c--;
1238            } while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL);
1239            if (i == n-1) {
1240                TEST_CHK(c == n);
1241            } else {
1242                TEST_CHK(c == -1);
1243            }
1244        }
1245    }
1246
1247    if (mask & 0x10000000) {
1248        for (i=0;i<n;++i){
1249            sprintf(key, keystr_mid, (int)i);
1250            s = fdb_iterator_seek(fit, key, strlen(key)+1, FDB_ITR_SEEK_LOWER);
1251            TEST_CHK(s == FDB_RESULT_SUCCESS);
1252            c = i;
1253            if (doc_status[c] == 2) {
1254                c--; // lower mode
1255            }
1256            do {
1257                s = fdb_iterator_get(fit, &doc);
1258                if (s != FDB_RESULT_SUCCESS) break;
1259                sprintf(key, keystr_mid, (int)c);
1260                c += ((doc_status[c] == 2)?(1):(0));
1261                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1262                TEST_CMP(doc->body, value, doc->bodylen);
1263                fdb_doc_free(doc);
1264                doc = NULL;
1265                c++;
1266            } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1267            TEST_CHK(c == n);
1268        }
1269    }
1270
1271    if (mask & 0x100000000) {
1272        for (i=0;i<n;++i){
1273            sprintf(key, keystr_mid, (int)i);
1274            s = fdb_iterator_seek(fit, key, strlen(key)+1, FDB_ITR_SEEK_LOWER);
1275            TEST_CHK(s == FDB_RESULT_SUCCESS);
1276            c = i;
1277            if (doc_status[c] == 2) {
1278                c--; // lower mode
1279            }
1280            do {
1281                s = fdb_iterator_get(fit, &doc);
1282                if (s != FDB_RESULT_SUCCESS) break;
1283                sprintf(key, keystr_mid, (int)c);
1284                c -= ((doc_status[c] == 2)?(1):(0));
1285                sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1286                TEST_CMP(doc->body, value, doc->bodylen);
1287                fdb_doc_free(doc);
1288                doc = NULL;
1289                c--;
1290            } while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL);
1291            TEST_CHK(c == -1);
1292        }
1293    }
1294
1295    if (mask & 0x1000000000) {
1296        s = fdb_iterator_seek_to_min(fit);
1297        TEST_CHK(s == FDB_RESULT_SUCCESS);
1298        c = 0;
1299        do {
1300            s = fdb_iterator_get(fit, &doc);
1301            if (s != FDB_RESULT_SUCCESS) break;
1302            sprintf(key, keystr_mid, (int)c);
1303            c += ((doc_status[c] == 2)?(1):(0));
1304            sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1305            TEST_CMP(doc->body, value, doc->bodylen);
1306            fdb_doc_free(doc);
1307            doc = NULL;
1308            c++;
1309        } while (fdb_iterator_next(fit) != FDB_RESULT_ITERATOR_FAIL);
1310        TEST_CHK(c == n);
1311
1312        s = fdb_iterator_seek_to_max(fit);
1313        TEST_CHK(s == FDB_RESULT_SUCCESS);
1314        c = n-1;
1315        do {
1316            s = fdb_iterator_get(fit, &doc);
1317            if (s != FDB_RESULT_SUCCESS) break;
1318            sprintf(key, keystr_mid, (int)c);
1319            c -= ((doc_status[c] == 2)?(1):(0));
1320            sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1321            TEST_CMP(doc->body, value, doc->bodylen);
1322            fdb_doc_free(doc);
1323            doc = NULL;
1324            c--;
1325        } while (fdb_iterator_prev(fit) != FDB_RESULT_ITERATOR_FAIL);
1326        TEST_CHK(c == -1);
1327    }
1328    s = fdb_iterator_close(fit);
1329    TEST_CHK(s == FDB_RESULT_SUCCESS);
1330
1331    if (mask & 0x10000000000) {
1332        // create an iterator with an end key and skip max key option
1333        i = n/3*2;
1334        sprintf(key, keystr, (int)i);
1335        s = fdb_iterator_init(db, &fit, NULL, 0, key, strlen(key)+1, FDB_ITR_SKIP_MAX_KEY);
1336        TEST_CHK(s == FDB_RESULT_SUCCESS);
1337        s = fdb_iterator_seek_to_max(fit);
1338        TEST_CHK(s == FDB_RESULT_SUCCESS);
1339        s = fdb_iterator_get(fit, &doc);
1340        TEST_CHK(s == FDB_RESULT_SUCCESS);
1341        c = i-1;
1342        sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1343        TEST_CMP(doc->body, value, doc->bodylen);
1344        fdb_doc_free(doc);
1345        doc = NULL;
1346        s = fdb_iterator_close(fit);
1347        TEST_CHK(s == FDB_RESULT_SUCCESS);
1348
1349        // create an iterator with an start key and skip min key option
1350        i = n/3;
1351        sprintf(key, keystr, (int)i);
1352        s = fdb_iterator_init(db, &fit, key, strlen(key)+1, NULL, 0, FDB_ITR_SKIP_MIN_KEY);
1353        TEST_CHK(s == FDB_RESULT_SUCCESS);
1354        s = fdb_iterator_seek_to_min(fit);
1355        TEST_CHK(s == FDB_RESULT_SUCCESS);
1356        s = fdb_iterator_get(fit, &doc);
1357        TEST_CHK(s == FDB_RESULT_SUCCESS);
1358        c = i+1;
1359        sprintf(value, (doc_status[c]==0)?(valuestr):(valuestr2), c);
1360        TEST_CMP(doc->body, value, doc->bodylen);
1361        fdb_doc_free(doc);
1362        doc = NULL;
1363        s = fdb_iterator_close(fit);
1364        TEST_CHK(s == FDB_RESULT_SUCCESS);
1365
1366        s = fdb_close(dbfile);
1367        TEST_CHK(s == FDB_RESULT_SUCCESS);
1368        s = fdb_shutdown();
1369        TEST_CHK(s == FDB_RESULT_SUCCESS);
1370        memleak_end();
1371    }
1372
1373    sprintf(cmd, "iterator complete test ");
1374    if (insert_opt == 0) {
1375        strcat(cmd, "(HB+trie: all, WAL: even");
1376    } else if (insert_opt == 1) {
1377        strcat(cmd, "(HB+trie: all, WAL: odd");
1378    } else if (insert_opt == 2) {
1379        strcat(cmd, "(HB+trie: odd, WAL: even");
1380    } else if (insert_opt == 3) {
1381        strcat(cmd, "(HB+trie: even, WAL: odd");
1382    } else if (insert_opt == 4) {
1383        strcat(cmd, "(HB+trie: all, WAL: empty");
1384    } else if (insert_opt == 5) {
1385        strcat(cmd, "(HB+trie: empty, WAL: all");
1386    } else if (insert_opt == 6) {
1387        strcat(cmd, "(HB+trie: all, WAL: all");
1388    }
1389    if (delete_opt) {
1390        strcat(cmd, ", doc deletion)");
1391    } else {
1392        strcat(cmd, ")");
1393    }
1394    TEST_RESULT(cmd);
1395}
1396
1397void iterator_extreme_key_test()
1398{
1399    TEST_INIT();
1400
1401    int n = 30;
1402    int i, r, c;
1403    char cmd[256];
1404    char key[256], value[256];
1405    char keyBuf[256], valueBuf[256];
1406    fdb_file_handle *dbfile;
1407    fdb_kvs_handle *db;
1408    fdb_config config;
1409    fdb_kvs_config kvs_config;
1410    fdb_doc *doc = NULL;
1411    fdb_iterator *fit;
1412    fdb_status s;
1413
1414    sprintf(cmd, SHELL_DEL " iterator_test*");
1415    r = system(cmd);
1416    (void)r;
1417
1418    memleak_start();
1419
1420    config = fdb_get_default_config();
1421    kvs_config = fdb_get_default_kvs_config();
1422    s = fdb_open(&dbfile, "./iterator_test", &config);
1423    TEST_CHK(s == FDB_RESULT_SUCCESS);
1424    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1425    TEST_CHK(s == FDB_RESULT_SUCCESS);
1426
1427    memset(key, 0xff, 256);
1428    for (i=1;i<n;i+=1){
1429        sprintf(value, "0xff length %d", (int)i);
1430        fdb_set_kv(db, key, i, value, strlen(value)+1);
1431    }
1432    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1433
1434    // Pre-allocate iterator return document memory and re-use the same
1435    s = fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
1436    TEST_CHK(s == FDB_RESULT_SUCCESS);
1437    doc->key = &keyBuf[0];
1438    doc->meta = NULL;
1439    doc->body = &valueBuf[0];
1440
1441    s = fdb_iterator_init(db, &fit, NULL, 0, NULL, 0, 0x0);
1442    TEST_CHK(s == FDB_RESULT_SUCCESS);
1443    s = fdb_iterator_seek_to_max(fit);
1444    TEST_CHK(s == FDB_RESULT_SUCCESS);
1445    c = n-1;
1446    while (s == FDB_RESULT_SUCCESS) {
1447        s = fdb_iterator_get(fit, &doc);
1448        if (s != FDB_RESULT_SUCCESS) {
1449            break;
1450        }
1451        sprintf(value, "0xff length %d", (int)c);
1452        TEST_CMP(doc->body, value, doc->bodylen);
1453        s = fdb_iterator_prev(fit);
1454        c--;
1455    }
1456
1457    i = 8;
1458    c = i;
1459    s = fdb_iterator_seek(fit, key, i, FDB_ITR_SEEK_LOWER);
1460    while (s == FDB_RESULT_SUCCESS) {
1461        s = fdb_iterator_get(fit, &doc);
1462        if (s != FDB_RESULT_SUCCESS) {
1463            break;
1464        }
1465        sprintf(value, "0xff length %d", (int)c);
1466        TEST_CMP(doc->body, value, doc->bodylen);
1467        s = fdb_iterator_prev(fit);
1468        c--;
1469    }
1470
1471    i = 8;
1472    c = i;
1473    s = fdb_iterator_seek(fit, key, i, FDB_ITR_SEEK_LOWER);
1474    while (s == FDB_RESULT_SUCCESS) {
1475        s = fdb_iterator_get(fit, &doc);
1476        if (s != FDB_RESULT_SUCCESS) {
1477            break;
1478        }
1479        sprintf(value, "0xff length %d", (int)c);
1480        TEST_CMP(doc->body, value, doc->bodylen);
1481        s = fdb_iterator_next(fit);
1482        c++;
1483    }
1484
1485    s = fdb_iterator_close(fit);
1486    TEST_CHK(s == FDB_RESULT_SUCCESS);
1487
1488    // Initialize iterator to an extreme non-existent end_key
1489    s = fdb_iterator_init(db, &fit, NULL, 0, key, 256, 0x0);
1490    TEST_CHK(s == FDB_RESULT_SUCCESS);
1491    s = fdb_iterator_seek_to_max(fit);
1492    TEST_CHK(s == FDB_RESULT_SUCCESS);
1493
1494    c = n-1;
1495    while (s == FDB_RESULT_SUCCESS) {
1496        s = fdb_iterator_get(fit, &doc);
1497        if (s != FDB_RESULT_SUCCESS) {
1498            break;
1499        }
1500        sprintf(value, "0xff length %d", (int)c);
1501        TEST_CMP(doc->body, value, doc->bodylen);
1502        s = fdb_iterator_prev(fit);
1503        c--;
1504    }
1505
1506    s = fdb_iterator_close(fit);
1507    TEST_CHK(s == FDB_RESULT_SUCCESS);
1508    s = fdb_close(dbfile);
1509    TEST_CHK(s == FDB_RESULT_SUCCESS);
1510
1511    // Release pre-allocated iterator return document buffer space
1512    doc->key = NULL;
1513    doc->body = NULL;
1514    s = fdb_doc_free(doc);
1515    TEST_CHK(s == FDB_RESULT_SUCCESS);
1516
1517    s = fdb_shutdown();
1518    TEST_CHK(s == FDB_RESULT_SUCCESS);
1519    memleak_end();
1520    TEST_RESULT("iterator extreme key test");
1521}
1522
1523void iterator_no_deletes_test()
1524{
1525
1526    TEST_INIT();
1527    memleak_start();
1528    int i, r, n = 10;
1529    fdb_file_handle *dbfile;
1530    fdb_kvs_handle  *kv;
1531    char keybuf[256], bodybuf[256];
1532    fdb_doc **doc = alca(fdb_doc*, n);
1533    fdb_doc *rdoc = NULL;
1534    fdb_iterator *it;
1535    fdb_status status;
1536
1537    // remove previous iterator_test files
1538    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
1539    (void)r;
1540
1541    fdb_config fconfig = fdb_get_default_config();
1542    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
1543    fconfig.wal_threshold = 1024;
1544    fconfig.flags = FDB_OPEN_FLAG_CREATE;
1545    fconfig.compaction_threshold = 0;
1546
1547    // open db
1548    fdb_open(&dbfile, "./iterator_test", &fconfig);
1549    fdb_kvs_open(dbfile, &kv, "all_docs",  &kvs_config);
1550
1551    // insert docs to kv
1552    for (i=0;i<n;++i){
1553        sprintf(keybuf, "key%d", i);
1554        sprintf(bodybuf, "body%d", i);
1555        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf), NULL, 0,
1556                       (void*)bodybuf, strlen(bodybuf));
1557        fdb_set(kv, doc[i]);
1558    }
1559
1560    // delete all docs
1561    for (i=0;i<n;i++){
1562        status = fdb_del_kv(kv, doc[i]->key, doc[i]->keylen);
1563        TEST_CHK(status == FDB_RESULT_SUCCESS);
1564    }
1565
1566    // commit
1567    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1568
1569    // set doc that was deleted
1570    status = fdb_set(kv, doc[2]);
1571    TEST_CHK(status == FDB_RESULT_SUCCESS);
1572
1573    // get doc from db and verify not-deleted
1574    fdb_doc_create(&rdoc, doc[2]->key, doc[2]->keylen, NULL, 0, NULL, 0);
1575    status = fdb_get(kv, rdoc);
1576    TEST_CHK(status == FDB_RESULT_SUCCESS);
1577    TEST_CHK(rdoc->deleted == false);
1578    fdb_doc_free(rdoc);
1579    rdoc = NULL;
1580
1581    // iterate over all docs to retrieve undeleted key
1582    status = fdb_iterator_init(kv, &it, NULL, 0, NULL, 0, FDB_ITR_NO_DELETES);
1583    TEST_CHK(status == FDB_RESULT_SUCCESS);
1584    status = fdb_iterator_get(it, &rdoc);
1585    TEST_CHK(status == FDB_RESULT_SUCCESS);
1586    if (status == FDB_RESULT_SUCCESS){
1587        fdb_doc_free(rdoc);
1588    }
1589    fdb_iterator_close(it);
1590
1591    for (i=0;i<n;++i){
1592        fdb_doc_free(doc[i]);
1593    }
1594
1595    fdb_kvs_close(kv);
1596    fdb_close(dbfile);
1597    fdb_shutdown();
1598
1599    memleak_end();
1600    TEST_RESULT("iterator no deletes test");
1601}
1602
1603void iterator_set_del_docs_test()
1604{
1605    TEST_INIT();
1606    memleak_start();
1607
1608    int r;
1609    int i, j, k, n=100;
1610    int expected_doc_count=0;
1611    char keybuf[256], metabuf[256], bodybuf[256];
1612    int val2;
1613    fdb_file_handle *dbfile;
1614    fdb_iterator *it;
1615    fdb_kvs_handle *kv1;
1616    fdb_kvs_info info;
1617    fdb_config fconfig = fdb_get_default_config();
1618    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
1619    fdb_doc **doc = alca(fdb_doc*, n);
1620    fdb_doc *vdoc;
1621    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
1622    (void)r;
1623
1624    fconfig.wal_threshold = 1024;
1625    fconfig.flags = FDB_OPEN_FLAG_CREATE;
1626    fconfig.compaction_threshold = 10;
1627
1628    fdb_open(&dbfile, "./iterator_test1", &fconfig);
1629    fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1630
1631    for(k=0;k<20;++k){
1632        // set n docs
1633        for(i=0;i<n;++i){
1634            sprintf(keybuf, "key%02d%03d", k, i);
1635            sprintf(metabuf, "meta%02d%03d", k, i);
1636            sprintf(bodybuf, "body%02d%03d", k, i);
1637            fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
1638                (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
1639            fdb_set(kv1, doc[i]);
1640            expected_doc_count++;
1641        }
1642
1643        // commit
1644        fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1645
1646        // delete subset of recently loaded docs
1647        for(j=n/4;j<n/2;j++){
1648            fdb_del(kv1, doc[j]);
1649            expected_doc_count--;
1650        }
1651        fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1652
1653        fdb_get_kvs_info(kv1, &info);
1654        if(info.doc_count != (size_t)expected_doc_count){
1655            // test already failed further debugging check info
1656            fdb_iterator_init(kv1, &it, NULL, 0,
1657                              NULL, 0, FDB_ITR_NONE);
1658            val2=0;
1659            do {
1660                fdb_iterator_get(it, &vdoc);
1661                if (!vdoc->deleted){
1662                    val2++;
1663                }
1664                fdb_doc_free(vdoc);
1665            } while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
1666            fdb_iterator_close(it);
1667            printf("dbdocs(%d) expected(%d)\n", val2, expected_doc_count);
1668        }
1669        TEST_CHK(info.doc_count == (size_t)expected_doc_count);
1670
1671        // preliminary cleanup
1672        for(i=0;i<n;++i){
1673            fdb_doc_free(doc[i]);
1674        }
1675    }
1676
1677    fdb_kvs_close(kv1);
1678    fdb_close(dbfile);
1679    fdb_shutdown();
1680    memleak_end();
1681
1682    TEST_RESULT("iterator set del docs");
1683}
1684
1685void iterator_del_next_test()
1686{
1687    TEST_INIT();
1688
1689    memleak_start();
1690
1691    int i, r;
1692    int n = 10;
1693    fdb_file_handle *dbfile;
1694    fdb_kvs_handle *db;
1695    fdb_doc **doc = alca(fdb_doc*, n);
1696    fdb_doc pre_alloc_doc;
1697    fdb_doc *rdoc = &pre_alloc_doc;
1698    fdb_status status;
1699    fdb_iterator *iterator;
1700
1701    char keybuf[256], metabuf[256], bodybuf[256];
1702    rdoc->key = keybuf;
1703    rdoc->meta = metabuf;
1704    rdoc->body = bodybuf;
1705
1706    // remove previous iterator_test files
1707    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
1708    (void)r;
1709
1710    fdb_config fconfig = fdb_get_default_config();
1711    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
1712    fconfig.buffercache_size = 0;
1713    fconfig.wal_threshold = 1024;
1714    fconfig.flags = FDB_OPEN_FLAG_CREATE;
1715    fconfig.compaction_threshold = 0;
1716
1717    // open db
1718    fdb_open(&dbfile, "./iterator_test1", &fconfig);
1719    fdb_kvs_open(dbfile, &db, "kv1", &kvs_config);
1720
1721    status = fdb_set_log_callback(db, logCallbackFunc,
1722                                  (void *) "iterator_del_next_test");
1723    TEST_CHK(status == FDB_RESULT_SUCCESS);
1724
1725    // insert documents of even number
1726    for (i=0;i<n;i+=2){
1727        sprintf(keybuf, "key%d", i);
1728        sprintf(metabuf, "meta%d", i);
1729        sprintf(bodybuf, "body%d", i);
1730        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
1731            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
1732        fdb_set(db, doc[i]);
1733    }
1734    // manually flush WAL & commit
1735    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1736
1737    // insert documents of odd number
1738    for (i=1;i<n;i+=2){
1739        sprintf(keybuf, "key%d", i);
1740        sprintf(metabuf, "meta%d", i);
1741        sprintf(bodybuf, "body%d", i);
1742        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
1743            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
1744        fdb_set(db, doc[i]);
1745    }
1746    // commit without WAL flush
1747    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1748
1749    // now even number docs are in hb-trie & odd number docs are in WAL
1750
1751    // create an iterator for full range
1752    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
1753
1754    // repeat until fail
1755    i=0;
1756    do {
1757        status = fdb_iterator_get(iterator, &rdoc);
1758        TEST_CHK(status == FDB_RESULT_SUCCESS);
1759
1760        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1761        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1762        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1763        // Delete the document to ensure that the iteration is not affected
1764        status = fdb_del(db, rdoc);
1765        TEST_CHK(status == FDB_RESULT_SUCCESS);
1766        status = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1767        TEST_CHK(status == FDB_RESULT_SUCCESS);
1768        i++;
1769    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1770    TEST_CHK(i==10);
1771
1772    // go back to start and retry iteration (should not be affected by deletes)
1773    status = fdb_iterator_seek_to_min(iterator);
1774    TEST_CHK(status == FDB_RESULT_SUCCESS);
1775
1776    // repeat full iteration until fail
1777    i=0;
1778    do {
1779        status = fdb_iterator_get(iterator, &rdoc);
1780        TEST_CHK(status == FDB_RESULT_SUCCESS);
1781
1782        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1783        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1784        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1785        i++;
1786    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1787    TEST_CHK(i==10);
1788
1789    fdb_iterator_close(iterator);
1790
1791    fdb_close(dbfile);
1792    fdb_shutdown();
1793
1794    // free all documents
1795    for (i=0;i<n;++i){
1796        fdb_doc_free(doc[i]);
1797    }
1798
1799    memleak_end();
1800
1801    TEST_RESULT("iterator del next test");
1802}
1803
1804void sequence_iterator_test()
1805{
1806    TEST_INIT();
1807
1808    memleak_start();
1809
1810    int i, r;
1811    int n = 10;
1812    int count;
1813    fdb_file_handle *dbfile;
1814    fdb_kvs_handle *db;
1815    fdb_doc **doc = alca(fdb_doc*, n);
1816    fdb_doc *rdoc = NULL;
1817    fdb_status status;
1818    fdb_iterator *iterator;
1819
1820    char keybuf[256], metabuf[256], bodybuf[256];
1821
1822    // remove previous iterator_test files
1823    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
1824    (void)r;
1825
1826    fdb_config fconfig = fdb_get_default_config();
1827    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
1828    fconfig.buffercache_size = 0;
1829    fconfig.wal_threshold = 1024;
1830    fconfig.flags = FDB_OPEN_FLAG_CREATE;
1831    fconfig.compaction_threshold = 0;
1832
1833    // open db
1834    fdb_open(&dbfile, "./iterator_test1", &fconfig);
1835    fdb_kvs_open_default(dbfile, &db, &kvs_config);
1836    status = fdb_set_log_callback(db, logCallbackFunc,
1837                                  (void *) "sequence_iterator_test");
1838    TEST_CHK(status == FDB_RESULT_SUCCESS);
1839
1840    // insert documents of even number
1841    for (i=0;i<n;i+=2){
1842        sprintf(keybuf, "key%d", i);
1843        sprintf(metabuf, "meta%d", i);
1844        sprintf(bodybuf, "body%d", i);
1845        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
1846            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
1847        fdb_set(db, doc[i]);
1848    }
1849    // manually flush WAL & commit
1850    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1851
1852    // insert documents of odd number
1853    for (i=1;i<n;i+=2){
1854        sprintf(keybuf, "key%d", i);
1855        sprintf(metabuf, "meta%d", i);
1856        sprintf(bodybuf, "body%d", i);
1857        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
1858            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
1859        fdb_set(db, doc[i]);
1860    }
1861    // commit without WAL flush
1862    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1863
1864    // now even number docs are in hb-trie & odd number docs are in WAL
1865
1866    // create an iterator over sequence number range over FULL RANGE
1867    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NONE);
1868
1869    // repeat until fail
1870    i=0;
1871    count = 0;
1872    do {
1873        status = fdb_iterator_get(iterator, &rdoc);
1874        TEST_CHK(status == FDB_RESULT_SUCCESS);
1875
1876        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1877        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1878        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1879
1880        fdb_doc_free(rdoc);
1881        rdoc = NULL;
1882        i = (i + 2 >= n) ? 1: i + 2; // by-seq, first come even docs, then odd
1883        count++;
1884    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1885    TEST_CHK(count==n);
1886    fdb_iterator_close(iterator);
1887
1888    // create an iterator over sequence number.
1889    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NONE);
1890
1891    // repeat until fail
1892    i=0;
1893    count = 0;
1894    do {
1895        status = fdb_iterator_get_metaonly(iterator, &rdoc);
1896        TEST_CHK(status == FDB_RESULT_SUCCESS);
1897
1898        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1899        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1900        TEST_CHK(rdoc->body == NULL);
1901
1902        fdb_doc_free(rdoc);
1903        rdoc = NULL;
1904        i = (i + 2 >= n) ? 1: i + 2; // by-seq, first come even docs, then odd
1905        count++;
1906    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1907    TEST_CHK(count==n);
1908    fdb_iterator_close(iterator);
1909
1910    // create another iterator starts from seq number 2 and ends at 9
1911    fdb_iterator_sequence_init(db, &iterator, 2, 7, FDB_ITR_NONE);
1912
1913    // repeat until fail
1914    i=2;
1915    count = 0;
1916    do {
1917        status = fdb_iterator_get(iterator, &rdoc);
1918        TEST_CHK(status == FDB_RESULT_SUCCESS);
1919
1920        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1921        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1922        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1923
1924        fdb_doc_free(rdoc);
1925        rdoc = NULL;
1926        i = (i + 2 >= n) ? 1: i + 2; // by-seq, first come even docs, then odd
1927        count++;
1928    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1929    TEST_CHK(count==6);
1930    fdb_iterator_close(iterator);
1931    // remove document #8 and #9
1932    fdb_doc_create(&rdoc, doc[8]->key, doc[8]->keylen, doc[8]->meta, doc[8]->metalen, NULL, 0);
1933    status = fdb_del(db, rdoc);
1934    TEST_CHK(status == FDB_RESULT_SUCCESS);
1935    fdb_doc_free(rdoc);
1936    rdoc = NULL;
1937    fdb_doc_create(&rdoc, doc[9]->key, doc[9]->keylen, doc[9]->meta, doc[9]->metalen, NULL, 0);
1938    status = fdb_del(db, rdoc);
1939    TEST_CHK(status == FDB_RESULT_SUCCESS);
1940    fdb_doc_free(rdoc);
1941    rdoc = NULL;
1942    // commit
1943    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1944
1945    // create an iterator for full range
1946    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NONE);
1947    // repeat until fail
1948    i=0;
1949    count=0;
1950    do {
1951        status = fdb_iterator_get(iterator, &rdoc);
1952        TEST_CHK(status == FDB_RESULT_SUCCESS);
1953
1954        if (count != 8 && count != 9) { // do not look validate key8 and key9
1955            TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1956            TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1957            TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1958        } else {
1959            TEST_CHK(rdoc->deleted == true);
1960        }
1961
1962        fdb_doc_free(rdoc);
1963        rdoc = NULL;
1964        // Turn around when we hit 8 as the last items, key8 and key9 are gone
1965        i = (i + 2 >= 8) ? 1: i + 2; // by-seq, first come even docs, then odd
1966        count++;
1967    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1968    TEST_CHK(count==10); // 10 items, with 2 deletions
1969    fdb_iterator_close(iterator);
1970
1971    // create an iterator for full range, but no deletes.
1972    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NO_DELETES);
1973    // repeat until fail
1974    i=0;
1975    count=0;
1976    do {
1977        status = fdb_iterator_get(iterator, &rdoc);
1978        TEST_CHK(status == FDB_RESULT_SUCCESS);
1979
1980        if (i != 8 && i != 9) { // key8 and key9 are deleted
1981            TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
1982            TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
1983            TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
1984        }
1985
1986        fdb_doc_free(rdoc);
1987        rdoc = NULL;
1988        i = (i + 2 >= 8) ? 1: i + 2; // by-seq, first come even docs, then odd
1989        count++;
1990    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
1991    TEST_CHK(count==8); // 10 items, with 2 deletions
1992    fdb_iterator_close(iterator);
1993
1994    // Update first document and test for absence of duplicates
1995    *((char *)doc[0]->body) = 'K'; // update key0 to Key0
1996    fdb_set(db, doc[0]);
1997    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1998
1999    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NO_DELETES);
2000    // repeat until fail
2001    i=2; // i == 0 should not appear until the end
2002    count=0;
2003    do {
2004        status = fdb_iterator_get(iterator, &rdoc);
2005        TEST_CHK(status == FDB_RESULT_SUCCESS);
2006
2007        if (i != 8 && i != 9) { // key8 and key9 are deleted
2008            TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2009            TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2010            TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2011        }
2012
2013        fdb_doc_free(rdoc);
2014        rdoc = NULL;
2015        i = (i + 2 >= 8) ? 1: i + 2; // by-seq, first come even docs, then odd
2016        if (count == 6) i = 0; // go back to test for i=0 at the end
2017        count++;
2018    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2019    TEST_CHK(count==8); // 10 items, with 2 deletions
2020    fdb_iterator_close(iterator);
2021
2022    // close db file
2023    fdb_kvs_close(db);
2024    fdb_close(dbfile);
2025
2026    // free all documents
2027    for (i=0;i<n;++i){
2028        fdb_doc_free(doc[i]);
2029    }
2030
2031    // free all resources
2032    fdb_shutdown();
2033
2034    memleak_end();
2035
2036    TEST_RESULT("sequence iterator test");
2037}
2038
2039void sequence_iterator_duplicate_test()
2040{
2041    // Unit test for MB-12225
2042    TEST_INIT();
2043
2044    memleak_start();
2045
2046    int i, r;
2047    int n = 100;
2048    int count;
2049    fdb_file_handle *dbfile;
2050    fdb_kvs_handle *db;
2051    fdb_doc **doc = alca(fdb_doc*, n);
2052    fdb_doc *rdoc = NULL;
2053    fdb_status status;
2054    fdb_iterator *iterator;
2055    fdb_seqnum_t seqnum;
2056
2057    char keybuf[256], metabuf[256], bodybuf[256];
2058
2059    // remove previous iterator_test files
2060    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2061    (void)r;
2062
2063    fdb_config fconfig = fdb_get_default_config();
2064    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2065    fconfig.buffercache_size = 0;
2066    fconfig.wal_threshold = 1024;
2067    fconfig.compaction_threshold = 0;
2068
2069    // open db
2070    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2071    fdb_kvs_open_default(dbfile, &db, &kvs_config);
2072    status = fdb_set_log_callback(db, logCallbackFunc,
2073                                  (void *) "sequence_iterator_test");
2074    TEST_CHK(status == FDB_RESULT_SUCCESS);
2075
2076    // insert documents first time
2077    for (i=0;i<n;i++){
2078        sprintf(keybuf, "key%d", i);
2079        sprintf(metabuf, "meta%d", i);
2080        sprintf(bodybuf, "body%d(first)", i);
2081        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2082            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2083        fdb_set(db, doc[i]);
2084    }
2085    // manually flush WAL & commit
2086    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2087
2088    // insert documents second time
2089    for (i=0;i<n;i++){
2090        sprintf(bodybuf, "body%d(second)", i);
2091        fdb_doc_update(&doc[i], NULL, 0, bodybuf, strlen(bodybuf));
2092        fdb_set(db, doc[i]);
2093    }
2094    // manually flush WAL & commit
2095    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2096
2097    // insert documents third time (only even number documents)
2098    for (i=0;i<n;i+=2){
2099        sprintf(bodybuf, "body%d(third)", i);
2100        fdb_doc_update(&doc[i], NULL, 0, bodybuf, strlen(bodybuf));
2101        fdb_set(db, doc[i]);
2102    }
2103    // commit without WAL flushing
2104    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2105
2106    // create an iterator over sequence number
2107    fdb_iterator_sequence_init(db, &iterator, 0, 220, FDB_ITR_NONE);
2108
2109    // repeat until fail
2110    count = 0;
2111    do {
2112        status = fdb_iterator_get(iterator, &rdoc);
2113        TEST_CHK(status == FDB_RESULT_SUCCESS);
2114        if (count<50) {
2115            // HB+trie
2116            i = count*2 + 1;
2117            seqnum = 100 + (count+1)*2;
2118            sprintf(bodybuf, "body%d(second)", i);
2119        } else {
2120            // WAL
2121            i = (count-50)*2;
2122            seqnum = 200 + (count-50+1);
2123            sprintf(bodybuf, "body%d(third)", i);
2124        }
2125
2126        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2127        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2128        TEST_CMP(rdoc->body, bodybuf, rdoc->bodylen);
2129        TEST_CHK(rdoc->seqnum == seqnum);
2130
2131        count++;
2132        fdb_doc_free(rdoc);
2133        rdoc = NULL;
2134    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2135    TEST_CHK(count==70);
2136    fdb_iterator_close(iterator);
2137
2138    // close db file
2139    fdb_kvs_close(db);
2140    fdb_close(dbfile);
2141    // free all documents
2142    for (i=0;i<n;++i){
2143        fdb_doc_free(doc[i]);
2144    }
2145    // free all resources
2146    fdb_shutdown();
2147
2148    memleak_end();
2149
2150    TEST_RESULT("sequence iterator duplicate test");
2151}
2152
2153void reverse_sequence_iterator_test()
2154{
2155    TEST_INIT();
2156
2157    memleak_start();
2158
2159    int i, r, count;
2160    int n = 10;
2161    fdb_file_handle *dbfile;
2162    fdb_kvs_handle *db;
2163    fdb_doc **doc = alca(fdb_doc*, n);
2164    fdb_doc *rdoc = NULL;
2165    fdb_status status;
2166    fdb_iterator *iterator;
2167
2168    char keybuf[256], metabuf[256], bodybuf[256];
2169
2170    // remove previous iterator_test files
2171    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2172    (void)r;
2173
2174    fdb_config fconfig = fdb_get_default_config();
2175    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2176    fconfig.buffercache_size = 0;
2177    fconfig.wal_threshold = 1024;
2178    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2179    fconfig.compaction_threshold = 0;
2180
2181    // open db
2182    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2183    fdb_kvs_open_default(dbfile, &db, &kvs_config);
2184    status = fdb_set_log_callback(db, logCallbackFunc,
2185                                  (void *) "reverse_sequence_iterator_test");
2186    TEST_CHK(status == FDB_RESULT_SUCCESS);
2187
2188    // insert documents of even number
2189    for (i=0;i<n;i+=2){
2190        sprintf(keybuf, "key%d", i);
2191        sprintf(metabuf, "meta%d", i);
2192        sprintf(bodybuf, "body%d", i);
2193        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2194            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2195        fdb_set(db, doc[i]);
2196    }
2197    // manually flush WAL & commit
2198    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2199
2200    // insert documents of odd number
2201    for (i=1;i<n;i+=2){
2202        sprintf(keybuf, "key%d", i);
2203        sprintf(metabuf, "meta%d", i);
2204        sprintf(bodybuf, "body%d", i);
2205        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2206            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2207        fdb_set(db, doc[i]);
2208    }
2209    // commit without WAL flush
2210    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2211
2212    // now even number docs are in hb-trie & odd number docs are in WAL
2213
2214    // First test reverse sequence iteration as it only involves btrees
2215    // create an iterator over sequence number range over FULL RANGE
2216    fdb_iterator_sequence_init(db, &iterator, 0, 0, FDB_ITR_NONE);
2217
2218    // move iterator forward up till middle...
2219    i=0;
2220    count = 0;
2221    do {
2222        status = fdb_iterator_get(iterator, &rdoc);
2223        TEST_CHK(status == FDB_RESULT_SUCCESS);
2224
2225        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2226        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2227        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2228
2229        fdb_doc_free(rdoc);
2230        rdoc = NULL;
2231        count++;
2232        if (i + 2 >= n) break;
2233        i = i + 2; // by-seq, first come even docs, then odd
2234    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2235    TEST_CHK(count==n/2);
2236
2237    // Now test reverse sequence iterator from mid-way..
2238
2239    i = i - 2;
2240    status = fdb_iterator_prev(iterator);
2241    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2242    status = fdb_iterator_get(iterator, &rdoc);
2243    TEST_CHK(status == FDB_RESULT_SUCCESS);
2244
2245    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2246    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2247    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2248
2249    fdb_doc_free(rdoc);
2250    rdoc = NULL;
2251    count++;
2252
2253    // change direction to forward again...
2254    TEST_CHK(fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2255    i = i + 2;
2256    do {
2257        status = fdb_iterator_get(iterator, &rdoc);
2258        TEST_CHK(status == FDB_RESULT_SUCCESS);
2259
2260        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2261        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2262        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2263
2264        fdb_doc_free(rdoc);
2265        rdoc = NULL;
2266        i = (i + 2 >= n) ? 1 : i + 2;// by-seq, first come even docs, then odd
2267        count++;
2268    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2269
2270    TEST_CHK(count==n+2); // two items were double counted due to reverse
2271
2272    // Reached End, now reverse iterate till start
2273    i = n - 1;
2274    count = n;
2275    status = fdb_iterator_prev(iterator);
2276    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2277    do {
2278        status = fdb_iterator_get(iterator, &rdoc);
2279        TEST_CHK(status == FDB_RESULT_SUCCESS);
2280
2281        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2282        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2283        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2284
2285        fdb_doc_free(rdoc);
2286        rdoc = NULL;
2287        i = (i - 2 < 0) ? n - 2 : i - 2;
2288        if (count) count--;
2289    } while (fdb_iterator_prev(iterator) != FDB_RESULT_ITERATOR_FAIL);
2290    TEST_CHK(count == 0);
2291    fdb_iterator_close(iterator);
2292
2293    // close db file
2294    fdb_kvs_close(db);
2295    fdb_close(dbfile);
2296
2297    // free all documents
2298    for (i=0;i<n;++i){
2299        fdb_doc_free(doc[i]);
2300    }
2301
2302    // free all resources
2303    fdb_shutdown();
2304
2305    memleak_end();
2306
2307    TEST_RESULT("reverse sequence iterator test");
2308}
2309
2310
2311void reverse_sequence_iterator_kvs_test()
2312{
2313
2314    TEST_INIT();
2315    memleak_start();
2316
2317    int i, r, count;
2318    int n = 10;
2319    fdb_file_handle *dbfile;
2320    fdb_kvs_handle *kv1, *kv2;
2321    fdb_doc **doc = alca(fdb_doc*, n);
2322    fdb_doc **doc2 = alca(fdb_doc*, n);
2323    fdb_doc *rdoc = NULL;
2324    fdb_status status;
2325    fdb_iterator *iterator;
2326    fdb_iterator *iterator2;
2327
2328    char keybuf[256], metabuf[256], bodybuf[256];
2329
2330    // remove previous iterator_test files
2331    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2332    (void)r;
2333
2334    fdb_config fconfig = fdb_get_default_config();
2335    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2336    fconfig.buffercache_size = 0;
2337    fconfig.wal_threshold = 1024;
2338    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2339    fconfig.compaction_threshold = 0;
2340
2341    // open db
2342    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2343    fdb_kvs_open_default(dbfile, &kv1, &kvs_config);
2344    status = fdb_set_log_callback(kv1, logCallbackFunc,
2345                                  (void *) "reverse_sequence_iterator_kvs_test");
2346    TEST_CHK(status == FDB_RESULT_SUCCESS);
2347
2348    // Create another KV store...
2349    status = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
2350    TEST_CHK(status == FDB_RESULT_SUCCESS);
2351
2352    // to 'kv2' with entire range
2353    for (i=0;i<n;++i) {
2354        sprintf(keybuf, "kEy%d", i);
2355        sprintf(metabuf, "mEta%d", i);
2356        sprintf(bodybuf, "bOdy%d", i);
2357        fdb_doc_create(&doc2[i], (void*)keybuf, strlen(keybuf),
2358            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2359        status = fdb_set(kv2, doc2[i]);
2360        TEST_CHK(status == FDB_RESULT_SUCCESS);
2361    }
2362
2363    // insert kv1 documents of even number
2364    for (i=0;i<n;i+=2) {
2365        sprintf(keybuf, "key%d", i);
2366        sprintf(metabuf, "meta%d", i);
2367        sprintf(bodybuf, "body%d", i);
2368        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2369            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2370        fdb_set(kv1, doc[i]);
2371    }
2372
2373    // manually flush WAL & commit
2374    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2375
2376    // insert kv1 documents of odd number
2377    for (i=1;i<n;i+=2) {
2378        sprintf(keybuf, "key%d", i);
2379        sprintf(metabuf, "meta%d", i);
2380        sprintf(bodybuf, "body%d", i);
2381        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2382            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2383        fdb_set(kv1, doc[i]);
2384    }
2385    // commit without WAL flush
2386    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2387
2388    // iterate even docs on kv1
2389    fdb_iterator_sequence_init(kv1, &iterator, 0, 0, FDB_ITR_NONE);
2390    i=0;
2391    count = 0;
2392    while (1) {
2393        status = fdb_iterator_get(iterator, &rdoc);
2394        TEST_CHK(!memcmp(rdoc->key, doc[i]->key, rdoc->keylen));
2395        TEST_CHK(!memcmp(rdoc->meta, doc[i]->meta, rdoc->metalen));
2396        TEST_CHK(!memcmp(rdoc->body, doc[i]->body, rdoc->bodylen));
2397        fdb_doc_free(rdoc);
2398        rdoc = NULL;
2399        count++;
2400        if (i + 2 >= n) {
2401            break;
2402        }
2403        i = i + 2; // by-seq, first come even docs, then odd
2404        status = fdb_iterator_next(iterator);
2405        if (status == FDB_RESULT_ITERATOR_FAIL) break;
2406    }
2407    TEST_CHK(count==n/2);
2408
2409    // iterate all docs over kv2
2410    fdb_iterator_sequence_init(kv2, &iterator2, 0, 0, FDB_ITR_NONE);
2411    TEST_CHK(status == FDB_RESULT_SUCCESS);
2412    while(1) {
2413        status = fdb_iterator_get(iterator2, &rdoc);
2414        TEST_CHK(status == FDB_RESULT_SUCCESS);
2415        fdb_doc_free(rdoc);
2416        rdoc = NULL;
2417        status = fdb_iterator_next(iterator2);
2418        if (status == FDB_RESULT_ITERATOR_FAIL) {
2419            break;
2420        }
2421    }
2422
2423    // manually flush WAL & commit
2424    // iterators should be unaffected
2425    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2426
2427    // reverse iterate even docs over kv1
2428     i = n - 4;
2429    count = 0;
2430    while (1) {
2431        status = fdb_iterator_prev(iterator);
2432        if (status == FDB_RESULT_ITERATOR_FAIL) {
2433            break;
2434        }
2435        status = fdb_iterator_get(iterator, &rdoc);
2436        TEST_CHK(status == FDB_RESULT_SUCCESS);
2437        TEST_CHK(!memcmp(rdoc->key, doc[i]->key, rdoc->keylen));
2438        TEST_CHK(!memcmp(rdoc->meta, doc[i]->meta, rdoc->metalen));
2439        TEST_CHK(!memcmp(rdoc->body, doc[i]->body, rdoc->bodylen));
2440        fdb_doc_free(rdoc);
2441        rdoc = NULL;
2442        i-=2;
2443        count++;
2444    }
2445
2446    TEST_CHK(count==4);
2447    fdb_iterator_close(iterator);
2448
2449    i = n-1;
2450    count = 0;
2451    // reverse iterate all docs over kv2
2452    while (1) {
2453        status = fdb_iterator_prev(iterator2);
2454        if (status == FDB_RESULT_ITERATOR_FAIL) {
2455            break;
2456        }
2457        status = fdb_iterator_get(iterator2, &rdoc);
2458        TEST_CHK(status == FDB_RESULT_SUCCESS);
2459        TEST_CHK(!memcmp(rdoc->key, doc2[i]->key, rdoc->keylen));
2460        TEST_CHK(!memcmp(rdoc->meta, doc2[i]->meta, rdoc->metalen));
2461        TEST_CHK(!memcmp(rdoc->body, doc2[i]->body, rdoc->bodylen));
2462        fdb_doc_free(rdoc);
2463        rdoc = NULL;
2464        i--;
2465        count++;
2466    }
2467    TEST_CHK(count==n);
2468    fdb_iterator_close(iterator2);
2469
2470    // re-open iterator after commit should return all docs for kv1
2471    i = 0;
2472    count = 0;
2473    fdb_iterator_sequence_init(kv1, &iterator, 0, 0, FDB_ITR_NONE);
2474    while (1) {
2475        status = fdb_iterator_get(iterator, &rdoc);
2476        TEST_CHK(status == FDB_RESULT_SUCCESS);
2477        TEST_CHK(!memcmp(rdoc->key, doc[i]->key, rdoc->keylen));
2478        TEST_CHK(!memcmp(rdoc->meta, doc[i]->meta, rdoc->metalen));
2479        TEST_CHK(!memcmp(rdoc->body, doc[i]->body, rdoc->bodylen));
2480        fdb_doc_free(rdoc);
2481        rdoc = NULL;
2482        if (i == 8) {
2483            i=1; // switch to odds
2484        } else {
2485            i+=2;
2486        }
2487        count++;
2488        status = fdb_iterator_next(iterator);
2489        if (status == FDB_RESULT_ITERATOR_FAIL) {
2490            break;
2491        }
2492    }
2493    TEST_CHK(count==n);
2494    fdb_iterator_close(iterator);
2495
2496    // free all documents
2497    for (i=0;i<n;++i) {
2498        fdb_doc_free(doc[i]);
2499        fdb_doc_free(doc2[i]);
2500    }
2501
2502    fdb_kvs_close(kv1);
2503    fdb_kvs_close(kv2);
2504    fdb_close(dbfile);
2505
2506    fdb_shutdown();
2507    memleak_end();
2508    TEST_RESULT("reverse sequence iterator kvs test");
2509
2510}
2511
2512void reverse_iterator_test()
2513{
2514    TEST_INIT();
2515
2516    memleak_start();
2517
2518    int i, r;
2519    int n = 10;
2520    fdb_file_handle *dbfile;
2521    fdb_kvs_handle *db;
2522    fdb_doc **doc = alca(fdb_doc*, n);
2523    fdb_doc *rdoc = NULL;
2524    fdb_status status;
2525    fdb_iterator *iterator;
2526
2527    char keybuf[256], metabuf[256], bodybuf[256];
2528
2529    // remove previous iterator_test files
2530    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2531    (void)r;
2532
2533    fdb_config fconfig = fdb_get_default_config();
2534    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2535    fconfig.buffercache_size = 0;
2536    fconfig.wal_threshold = 1024;
2537    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2538    fconfig.compaction_threshold = 0;
2539
2540    // open db
2541    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2542    fdb_kvs_open_default(dbfile, &db, &kvs_config);
2543    status = fdb_set_log_callback(db, logCallbackFunc,
2544                                  (void *) "reverse_iterator_test");
2545    TEST_CHK(status == FDB_RESULT_SUCCESS);
2546
2547    // insert documents of even number
2548    for (i=0;i<n;i+=2){
2549        sprintf(keybuf, "key%d", i);
2550        sprintf(metabuf, "meta%d", i);
2551        sprintf(bodybuf, "body%d", i);
2552        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2553            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2554        fdb_set(db, doc[i]);
2555    }
2556    // manually flush WAL & commit
2557    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
2558
2559    // insert documents of odd number
2560    for (i=1;i<n;i+=2){
2561        sprintf(keybuf, "key%d", i);
2562        sprintf(metabuf, "meta%d", i);
2563        sprintf(bodybuf, "body%d", i);
2564        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2565            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2566        fdb_set(db, doc[i]);
2567    }
2568    // commit without WAL flush
2569    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2570
2571    // now even number docs are in hb-trie & odd number docs are in WAL
2572
2573    // Reverse iteration over key range which involves hb-tries
2574    // create an iterator for full range
2575    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
2576
2577    // first test forward iterator - repeat until fail
2578    i=0;
2579    do {
2580        status = fdb_iterator_get(iterator, &rdoc);
2581        TEST_CHK(status == FDB_RESULT_SUCCESS);
2582
2583        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2584        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2585        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2586
2587        fdb_doc_free(rdoc);
2588        rdoc = NULL;
2589        i++;
2590    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2591    TEST_CHK(i==10);
2592
2593    // Now test reverse iterator..
2594    for (--i; fdb_iterator_prev(iterator) != FDB_RESULT_ITERATOR_FAIL; --i) {
2595        status = fdb_iterator_get(iterator, &rdoc);
2596        TEST_CHK(status == FDB_RESULT_SUCCESS);
2597
2598        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2599        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2600        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2601
2602        fdb_doc_free(rdoc);
2603        rdoc = NULL;
2604        if (i == 5) break; // Change direction at half point
2605    }
2606    TEST_CHK(i == 5);
2607
2608    // Mid-way reverse direction, again test forward iterator...
2609    i++;
2610    status = fdb_iterator_next(iterator);
2611    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2612    status = fdb_iterator_get(iterator, &rdoc);
2613    TEST_CHK(status == FDB_RESULT_SUCCESS);
2614
2615    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2616    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2617    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2618
2619    fdb_doc_free(rdoc);
2620    rdoc = NULL;
2621
2622    // Mid-way reverse direction, again test forward iterator...
2623    i++;
2624    status = fdb_iterator_next(iterator);
2625    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2626    status = fdb_iterator_get(iterator, &rdoc);
2627    TEST_CHK(status == FDB_RESULT_SUCCESS);
2628
2629    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2630    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2631    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2632
2633    fdb_doc_free(rdoc);
2634    rdoc = NULL;
2635
2636    // Again change direction and test reverse iterator..
2637    for (--i; fdb_iterator_prev(iterator) != FDB_RESULT_ITERATOR_FAIL; --i) {
2638        status = fdb_iterator_get(iterator, &rdoc);
2639        TEST_CHK(status == FDB_RESULT_SUCCESS);
2640
2641        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2642        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2643        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2644
2645        fdb_doc_free(rdoc);
2646        rdoc = NULL;
2647    }
2648    TEST_CHK(i == -1);
2649
2650    // Reached end - now test forward iterator...
2651    TEST_CHK(fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2652    i++;
2653    do {
2654        status = fdb_iterator_get(iterator, &rdoc);
2655        TEST_CHK(status == FDB_RESULT_SUCCESS);
2656
2657        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2658        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2659        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2660
2661        fdb_doc_free(rdoc);
2662        rdoc = NULL;
2663        i++;
2664    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2665    TEST_CHK(i==10);
2666
2667    fdb_iterator_close(iterator);
2668
2669    // close db file
2670    fdb_kvs_close(db);
2671    fdb_close(dbfile);
2672
2673    // free all documents
2674    for (i=0;i<n;++i){
2675        fdb_doc_free(doc[i]);
2676    }
2677
2678    // free all resources
2679    fdb_shutdown();
2680
2681    memleak_end();
2682
2683    TEST_RESULT("reverse iterator test");
2684}
2685
2686void iterator_seek_wal_only_test()
2687{
2688    TEST_INIT();
2689
2690    memleak_start();
2691
2692    int i, r;
2693    int n = 10;
2694    fdb_file_handle *dbfile;
2695    fdb_kvs_handle *db, *kv1;
2696    fdb_doc **doc = alca(fdb_doc*, n);
2697    fdb_doc *rdoc = NULL;
2698    fdb_status status;
2699    fdb_iterator *iterator;
2700
2701    char keybuf[256], metabuf[256], bodybuf[256];
2702
2703    // remove previous iterator_test files
2704    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2705    (void)r;
2706
2707    fdb_config fconfig = fdb_get_default_config();
2708    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2709    fconfig.buffercache_size = 0;
2710    fconfig.wal_threshold = 1024;
2711    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2712    fconfig.compaction_threshold = 0;
2713
2714    // open db
2715    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2716    fdb_kvs_open_default(dbfile, &db, &kvs_config);
2717    status = fdb_set_log_callback(db, logCallbackFunc,
2718                                  (void *) "iterator_seek_wal_only_test");
2719    TEST_CHK(status == FDB_RESULT_SUCCESS);
2720
2721    // Create another KV store..
2722    status = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
2723    TEST_CHK(status == FDB_RESULT_SUCCESS);
2724
2725    // insert using 'kv1' instance to ensure it does not interfere
2726    for (i=0;i<n;++i){
2727        sprintf(keybuf, "kEy%d", i);
2728        sprintf(metabuf, "mEta%d", i);
2729        sprintf(bodybuf, "bOdy%d", i);
2730        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2731            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2732        status = fdb_set(kv1, doc[i]);
2733        TEST_CHK(status == FDB_RESULT_SUCCESS);
2734        fdb_doc_free(doc[i]);
2735    }
2736
2737    // insert all documents into WAL only
2738    for (i=0;i<n;++i){
2739        sprintf(keybuf, "key%d", i);
2740        sprintf(metabuf, "meta%d", i);
2741        sprintf(bodybuf, "body%d", i);
2742        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2743            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2744        fdb_set(db, doc[i]);
2745    }
2746    // commit without WAL flush
2747    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2748
2749    // create an iterator for full range
2750    fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
2751
2752    // seek current iterator to inside the WAL's avl tree..
2753    status = fdb_iterator_get(iterator, &rdoc);
2754    TEST_CHK(status == FDB_RESULT_SUCCESS);
2755
2756    TEST_CMP(rdoc->key, doc[0]->key, rdoc->keylen);
2757    TEST_CMP(rdoc->meta, doc[0]->meta, rdoc->metalen);
2758    TEST_CMP(rdoc->body, doc[0]->body, rdoc->bodylen);
2759    fdb_doc_free(rdoc);
2760    rdoc = NULL;
2761
2762    // seek forward to 2nd key ..
2763    i=2;
2764    status = fdb_iterator_seek(iterator, doc[i]->key, strlen(keybuf), 0);
2765    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2766    status = fdb_iterator_get(iterator, &rdoc);
2767    TEST_CHK(status == FDB_RESULT_SUCCESS);
2768
2769    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2770    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2771    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2772    fdb_doc_free(rdoc);
2773    rdoc = NULL;
2774
2775    // iterator should be able to proceed forward
2776    status = fdb_iterator_next(iterator);
2777    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2778    status = fdb_iterator_get(iterator, &rdoc);
2779    TEST_CHK(status == FDB_RESULT_SUCCESS);
2780
2781    i++;
2782    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2783    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2784    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2785    fdb_doc_free(rdoc);
2786    rdoc = NULL;
2787
2788    // seek forward to the last key.
2789    status = fdb_iterator_seek(iterator, doc[n-1]->key, strlen(keybuf), 0);
2790    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2791    status = fdb_iterator_get(iterator, &rdoc);
2792    TEST_CHK(status == FDB_RESULT_SUCCESS);
2793
2794    TEST_CMP(rdoc->key, doc[n-1]->key, rdoc->keylen);
2795    TEST_CMP(rdoc->meta, doc[n-1]->meta, rdoc->metalen);
2796    TEST_CMP(rdoc->body, doc[n-1]->body, rdoc->bodylen);
2797    fdb_doc_free(rdoc);
2798    rdoc = NULL;
2799
2800    // seek backward to start key ..
2801    i = 0;
2802    status = fdb_iterator_seek(iterator, doc[i]->key, strlen(keybuf), 0);
2803    TEST_CHK(status != FDB_RESULT_ITERATOR_FAIL);
2804    status = fdb_iterator_get(iterator, &rdoc);
2805    TEST_CHK(status == FDB_RESULT_SUCCESS);
2806
2807    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2808    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2809    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2810    fdb_doc_free(rdoc);
2811    rdoc = NULL;
2812
2813    // seek forward to key2 ..
2814    status = fdb_iterator_seek(iterator, doc[2]->key, strlen(keybuf), 0);
2815    TEST_CHK(status == FDB_RESULT_SUCCESS);
2816
2817    i=2;
2818    do {
2819        status = fdb_iterator_get(iterator, &rdoc);
2820        TEST_CHK(status == FDB_RESULT_SUCCESS);
2821
2822        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2823        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2824        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2825
2826        fdb_doc_free(rdoc);
2827        rdoc = NULL;
2828        i++;
2829    } while(fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2830    TEST_CHK(i==10);
2831
2832    // Seek backward again to a key...
2833    status = fdb_iterator_seek(iterator, doc[3]->key, strlen(keybuf), 0);
2834    TEST_CHK(status == FDB_RESULT_SUCCESS);
2835
2836    i=3;
2837    do {
2838        status = fdb_iterator_get(iterator, &rdoc);
2839        TEST_CHK(status == FDB_RESULT_SUCCESS);
2840
2841        TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2842        TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2843        TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2844
2845        fdb_doc_free(rdoc);
2846        rdoc = NULL;
2847        i++;
2848    } while (fdb_iterator_next(iterator) != FDB_RESULT_ITERATOR_FAIL);
2849    TEST_CHK(i==10);
2850
2851    fdb_iterator_close(iterator);
2852
2853    // Test fdb_iterator_seek_to_max with key range
2854    // create an iterator for range of doc[4] ~ doc[8]
2855    sprintf(keybuf, "key%d", 4); // reuse buffer for start key
2856    sprintf(metabuf, "key%d", 8); // reuse buffer for end_key
2857    status = fdb_iterator_init(db, &iterator, keybuf, strlen(keybuf),
2858                      metabuf, strlen(metabuf),
2859                      FDB_ITR_NO_DELETES);
2860    TEST_CHK(status == FDB_RESULT_SUCCESS);
2861    i = 8;
2862    status = fdb_iterator_seek_to_max(iterator);
2863    TEST_CHK(status == FDB_RESULT_SUCCESS);
2864    status = fdb_iterator_get(iterator, &rdoc);
2865    TEST_CHK(status == FDB_RESULT_SUCCESS);
2866
2867    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2868    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2869    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2870    fdb_doc_free(rdoc);
2871    rdoc = NULL;
2872
2873    // test fdb_iterator_seek_to_min
2874    i = 4;
2875    status = fdb_iterator_seek_to_min(iterator);
2876    TEST_CHK(status == FDB_RESULT_SUCCESS);
2877    status = fdb_iterator_get(iterator, &rdoc);
2878    TEST_CHK(status == FDB_RESULT_SUCCESS);
2879
2880    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2881    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2882    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2883    fdb_doc_free(rdoc);
2884    rdoc = NULL;
2885
2886    status = fdb_iterator_close(iterator);
2887    TEST_CHK(status == FDB_RESULT_SUCCESS);
2888
2889    // Test fdb_iterator_seek_to_max over full range
2890    status = fdb_iterator_init(db, &iterator, NULL, 0, NULL, 0, FDB_ITR_NONE);
2891    TEST_CHK(status == FDB_RESULT_SUCCESS);
2892
2893    i = n - 1;
2894    status = fdb_iterator_seek_to_max(iterator);
2895    TEST_CHK(status == FDB_RESULT_SUCCESS);
2896    status = fdb_iterator_get(iterator, &rdoc);
2897    TEST_CHK(status == FDB_RESULT_SUCCESS);
2898
2899    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2900    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2901    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2902    fdb_doc_free(rdoc);
2903    rdoc = NULL;
2904
2905    // test fdb_iterator_seek_to_min
2906    i = 0;
2907    status = fdb_iterator_seek_to_min(iterator);
2908    TEST_CHK(status == FDB_RESULT_SUCCESS);
2909    status = fdb_iterator_get(iterator, &rdoc);
2910    TEST_CHK(status == FDB_RESULT_SUCCESS);
2911
2912    TEST_CMP(rdoc->key, doc[i]->key, rdoc->keylen);
2913    TEST_CMP(rdoc->meta, doc[i]->meta, rdoc->metalen);
2914    TEST_CMP(rdoc->body, doc[i]->body, rdoc->bodylen);
2915    fdb_doc_free(rdoc);
2916    rdoc = NULL;
2917
2918    status = fdb_iterator_close(iterator);
2919    TEST_CHK(status == FDB_RESULT_SUCCESS);
2920
2921    // close the kvs kv1
2922    fdb_kvs_close(kv1);
2923    // close db file
2924    fdb_kvs_close(db);
2925    fdb_close(dbfile);
2926
2927    // free all documents
2928    for (i=0;i<n;++i){
2929        fdb_doc_free(doc[i]);
2930    }
2931
2932    // free all resources
2933    fdb_shutdown();
2934
2935    memleak_end();
2936
2937    TEST_RESULT("iterator seek wal only test");
2938}
2939
2940void iterator_after_wal_threshold()
2941{
2942    TEST_INIT();
2943    memleak_start();
2944
2945    int i, r;
2946    int n = 600;
2947    char keybuf[256], bodybuf[256];
2948    fdb_file_handle *dbfile;
2949    fdb_kvs_handle *db, *db2;
2950    fdb_doc *rdoc = NULL;
2951    fdb_status status;
2952    fdb_iterator *it;
2953    fdb_config fconfig = fdb_get_default_config();
2954    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
2955    fconfig.wal_threshold = 1024;
2956    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2957
2958    // remove previous iterator_test files
2959    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
2960    (void)r;
2961
2962    // open db
2963    fdb_open(&dbfile, "./iterator_test1", &fconfig);
2964    fdb_kvs_open(dbfile, &db, "db1", &kvs_config);
2965    fdb_kvs_open(dbfile, &db2, "db2", &kvs_config);
2966
2967    // write 600 docs
2968    for (i=0;i<n;++i){
2969        sprintf(keybuf, "key%d", i);
2970        sprintf(bodybuf, "body%d", i);
2971        fdb_set_kv(db, keybuf, strlen(keybuf), bodybuf, strlen(bodybuf));
2972    }
2973
2974    // copy keys into another kv
2975    status = fdb_iterator_sequence_init(db, &it, 0, 0, FDB_ITR_NONE);
2976    TEST_CHK(status == FDB_RESULT_SUCCESS);
2977    do {
2978            status = fdb_iterator_get(it, &rdoc);
2979            TEST_CHK(status == FDB_RESULT_SUCCESS);
2980            status = fdb_set_kv(db2, rdoc->key, rdoc->keylen, NULL, 0);
2981            TEST_CHK(status == FDB_RESULT_SUCCESS);
2982            fdb_doc_free(rdoc);
2983            rdoc = NULL;
2984    } while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
2985    fdb_iterator_close(it);
2986
2987
2988    // verify read docs
2989    status = fdb_iterator_sequence_init(db, &it, 0, 0, FDB_ITR_NONE);
2990    TEST_CHK(status == FDB_RESULT_SUCCESS);
2991     do {
2992            status = fdb_iterator_get(it, &rdoc);
2993            TEST_CHK(status == FDB_RESULT_SUCCESS);
2994            status = fdb_get(db, rdoc);
2995            TEST_CHK(status == FDB_RESULT_SUCCESS);
2996            fdb_doc_free(rdoc);
2997            rdoc = NULL;
2998    } while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
2999    fdb_iterator_close(it);
3000
3001    fdb_kvs_close(db);
3002    fdb_kvs_close(db2);
3003    fdb_close(dbfile);
3004    fdb_shutdown();
3005
3006    memleak_end();
3007    TEST_RESULT("iterator after wal threshold");
3008}
3009
3010void iterator_manual_wal_flush()
3011{
3012    TEST_INIT();
3013    memleak_start();
3014
3015    int r;
3016    unsigned char key1[] =       { 8,  5, 62, 62, 52, 50, 48, 49,
3017                                  45,  0,  6, 49,  0,  0,  0};
3018    unsigned char key2[] =       { 8,  5, 62, 62, 52, 50, 48, 49,
3019                                  49, 45,  0,  6, 49, 50,  0,  0,
3020                                   0};
3021    unsigned char start_key1[] = { 8,  5, 62, 62, 52, 49, 57, 57,
3022                                  57, 45,  0};
3023    unsigned char start_key2[] = { 8,  5, 62, 62, 52, 51, 52, 53,
3024                                  10, 20,  0};
3025    fdb_file_handle *dbfile;
3026    fdb_kvs_handle *db, *db2;
3027    fdb_doc *rdoc = NULL;
3028    fdb_status status;
3029    fdb_iterator *it;
3030    fdb_config fconfig = fdb_get_default_config();
3031    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
3032    fconfig.wal_threshold = 1024;
3033    fconfig.flags = FDB_OPEN_FLAG_CREATE;
3034
3035    // remove previous iterator_test files
3036    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
3037    (void)r;
3038
3039    // open db
3040    fdb_open(&dbfile, "./iterator_test1", &fconfig);
3041    fdb_kvs_open(dbfile, &db, "db1", &kvs_config);
3042    fdb_kvs_open(dbfile, &db2, "db2", &kvs_config);
3043
3044    fdb_set_kv(db, key1, sizeof(key1), NULL, 0);
3045    fdb_set_kv(db, key2, sizeof(key2), NULL, 0);
3046
3047    // normal commit
3048    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
3049
3050    // start_key's skipped prefix is smaller than the common prefix
3051    status = fdb_iterator_init(db, &it, start_key1, sizeof(start_key1),
3052                               NULL, 0, FDB_ITR_NONE);
3053    TEST_CHK(status == FDB_RESULT_SUCCESS);
3054    do {
3055        status = fdb_iterator_get(it, &rdoc);
3056        TEST_CHK(status == FDB_RESULT_SUCCESS);
3057        fdb_doc_free(rdoc);
3058        rdoc = NULL;
3059    } while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
3060    fdb_iterator_close(it);
3061
3062    // start_key's skipped prefix is gerater than the common prefix
3063    status = fdb_iterator_init(db, &it, start_key2, sizeof(start_key2),
3064                               NULL, 0, FDB_ITR_NONE);
3065    TEST_CHK(status == FDB_RESULT_SUCCESS);
3066    status = fdb_iterator_get(it, &rdoc);
3067    TEST_CHK(status != FDB_RESULT_SUCCESS);
3068    fdb_iterator_close(it);
3069
3070    fdb_set_kv(db2, key1, sizeof(key1), NULL, 0);
3071    fdb_set_kv(db2, key2, sizeof(key2), NULL, 0);
3072
3073    // manually flush WAL & commit
3074    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
3075
3076    // start_key's skipped prefix is smaller than the common prefix
3077    status = fdb_iterator_init(db2, &it, start_key1, sizeof(start_key1),
3078                               NULL, 0, FDB_ITR_NONE);
3079    TEST_CHK(status == FDB_RESULT_SUCCESS);
3080    do {
3081        status = fdb_iterator_get(it, &rdoc);
3082        TEST_CHK(status == FDB_RESULT_SUCCESS);
3083        fdb_doc_free(rdoc);
3084        rdoc = NULL;
3085    } while (fdb_iterator_next(it) != FDB_RESULT_ITERATOR_FAIL);
3086    fdb_iterator_close(it);
3087
3088    // start_key's skipped prefix is gerater than the common prefix
3089    status = fdb_iterator_init(db, &it, start_key2, sizeof(start_key2),
3090                               NULL, 0, FDB_ITR_NONE);
3091    TEST_CHK(status == FDB_RESULT_SUCCESS);
3092    status = fdb_iterator_get(it, &rdoc);
3093    TEST_CHK(status != FDB_RESULT_SUCCESS);
3094    fdb_iterator_close(it);
3095
3096    // start_key's skipped prefix is smaller than the common prefix
3097    status = fdb_iterator_init(db2, &it, NULL, 0,
3098                               start_key1, sizeof(start_key1), FDB_ITR_NONE);
3099    TEST_CHK(status == FDB_RESULT_SUCCESS);
3100    status = fdb_iterator_seek(it, start_key1, sizeof(start_key1), FDB_ITR_SEEK_LOWER);
3101    TEST_CHK(status != FDB_RESULT_SUCCESS);
3102    fdb_iterator_close(it);
3103
3104    // start_key's skipped prefix is gerater than the common prefix
3105    status = fdb_iterator_init(db, &it, NULL, 0,
3106                               start_key2, sizeof(start_key2), FDB_ITR_NONE);
3107    TEST_CHK(status == FDB_RESULT_SUCCESS);
3108    status = fdb_iterator_seek(it, start_key2, sizeof(start_key2), FDB_ITR_SEEK_LOWER);
3109    TEST_CHK(status == FDB_RESULT_SUCCESS);
3110    status = fdb_iterator_get(it, &rdoc);
3111    TEST_CHK(status == FDB_RESULT_SUCCESS);
3112    fdb_doc_free(rdoc);
3113    rdoc = NULL;
3114    while (fdb_iterator_prev(it) != FDB_RESULT_ITERATOR_FAIL) {
3115        status = fdb_iterator_get(it, &rdoc);
3116        TEST_CHK(status == FDB_RESULT_SUCCESS);
3117        fdb_doc_free(rdoc);
3118        rdoc = NULL;
3119    }
3120    fdb_iterator_close(it);
3121
3122    fdb_close(dbfile);
3123    fdb_shutdown();
3124
3125    memleak_end();
3126    TEST_RESULT("iterator manual wal flush");
3127}
3128
3129void iterator_concurrent_compaction()
3130{
3131    TEST_INIT();
3132    memleak_start();
3133
3134    int i, r;
3135    int n = 10;
3136    char keybuf[256], bodybuf[256];
3137    fdb_file_handle *dbfile, *dbfile2;
3138    fdb_kvs_handle *db, *db2;
3139    fdb_doc *rdoc = NULL;
3140    fdb_status status;
3141    fdb_iterator *it_id, *it_seq;
3142    fdb_config fconfig = fdb_get_default_config();
3143    fdb_kvs_config kvs_config = fdb_get_default_kvs_config();
3144    void *value_out;
3145    size_t valuelen_out;
3146
3147    fconfig.wal_threshold = 1024;
3148    fconfig.flags = FDB_OPEN_FLAG_CREATE;
3149
3150    // remove previous iterator_test files
3151    r = system(SHELL_DEL" iterator_test* > errorlog.txt");
3152    (void)r;
3153
3154    // open db
3155    fdb_open(&dbfile, "./iterator_test1", &fconfig);
3156    fdb_kvs_open(dbfile, &db, "db", &kvs_config);
3157
3158    // write docs
3159    for (i=0;i<n;++i){
3160        sprintf(keybuf, "key%d", i);
3161        sprintf(bodybuf, "body%d", i);
3162        fdb_set_kv(db, keybuf, strlen(keybuf), bodybuf, strlen(bodybuf));
3163    }
3164    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
3165
3166    fdb_open(&dbfile2, "./iterator_test1", &fconfig);
3167    fdb_kvs_open(dbfile2, &db2, "db", &kvs_config);
3168
3169    fdb_compact(dbfile, "./iterator_test2");
3170
3171    status = fdb_iterator_init(db2, &it_id, NULL, 0, NULL, 0, 0x0);
3172    TEST_CHK(status == FDB_RESULT_SUCCESS);
3173    status = fdb_iterator_sequence_init(db, &it_seq, 0, 0, 0x0);
3174    TEST_CHK(status == FDB_RESULT_SUCCESS);
3175
3176    // retrieve docs
3177    // now handle's header is updated
3178    for (i=0;i<n;++i){
3179        sprintf(keybuf, "key%d", i);
3180        fdb_get_kv(db, keybuf, strlen(keybuf), &value_out, &valuelen_out);
3181        fdb_free_block(value_out);
3182    }
3183
3184    do {
3185        rdoc = NULL;
3186        status = fdb_iterator_get(it_id, &rdoc);
3187        TEST_CHK(status == FDB_RESULT_SUCCESS);
3188        fdb_doc_free(rdoc);
3189    } while (fdb_iterator_next(it_id) != FDB_RESULT_ITERATOR_FAIL);
3190    status = fdb_iterator_close(it_id);
3191    TEST_CHK(