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// lexicographically compares two variable-length binary streams
34#define MIN(a,b) (((a)<(b))?(a):(b))
35static int _multi_kv_test_keycmp(void *key1, size_t keylen1, void *key2, size_t keylen2)
36{
37    if (keylen1 == keylen2) {
38        return memcmp(key1, key2, keylen1);
39    }else {
40        size_t len = MIN(keylen1, keylen2);
41        int cmp = memcmp(key1, key2, len);
42        if (cmp != 0) return cmp;
43        else {
44            return (int)((int)keylen1 - (int)keylen2);
45        }
46    }
47}
48
49
50#define MULTI_KV_VAR_CMP (0x1)
51void multi_kv_test(uint8_t opt, size_t chunksize)
52{
53    TEST_INIT();
54
55    int n = 100;
56    int i, r;
57    char key[256], meta[256], value[256];
58    char keystr[] = "key%06d";
59    char metastr[] = "meta%06d";
60    char metastr_kv[] = "meta%06d(kv)";
61    char valuestr[] = "value%08d";
62    char valuestr_kv[] = "value%08d (kv instance)";
63    void *value_out;
64    size_t valuelen;
65
66    char *kvs_names[] = {NULL, (char*)"kv1"};
67    fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp,
68                                           _multi_kv_test_keycmp};
69
70    fdb_file_handle *dbfile;
71    fdb_kvs_handle *db, *kv1;
72    fdb_config config;
73    fdb_kvs_config kvs_config;
74    fdb_doc *doc;
75    fdb_file_info file_info;
76    fdb_kvs_info kvs_info;
77    fdb_status s;
78
79    sprintf(value, SHELL_DEL" multi_kv_test*");
80    r = system(value);
81    (void)r;
82
83    memleak_start();
84
85    config = fdb_get_default_config();
86    kvs_config = fdb_get_default_kvs_config();
87    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
88    config.chunksize = chunksize;
89    config.multi_kv_instances = true;
90    config.wal_threshold = 50;
91    config.buffercache_size = 0;
92
93    s = fdb_open(&dbfile, "./multi_kv_test", &config);
94    TEST_CHK(s == FDB_RESULT_SUCCESS);
95    if (opt & MULTI_KV_VAR_CMP) {
96        kvs_config.custom_cmp = _multi_kv_test_keycmp;
97    }
98    s = fdb_kvs_open_default(dbfile, &db, &kvs_config);
99    TEST_CHK(s == FDB_RESULT_SUCCESS);
100
101    // insert using 'default' instance
102    for (i=0;i<n;++i) {
103        sprintf(key, keystr, i);
104        sprintf(meta, metastr, i);
105        sprintf(value, valuestr, i);
106        fdb_doc_create(&doc, key, strlen(key)+1, meta,
107                           strlen(meta)+1, value, strlen(value)+1);
108        s = fdb_set(db, doc);
109        TEST_CHK(s == FDB_RESULT_SUCCESS);
110        fdb_doc_free(doc);
111    }
112
113    // retrieve from WAL
114    for (i=0;i<n;++i){
115        // by key
116        sprintf(key, keystr, i);
117        sprintf(meta, metastr, i);
118        sprintf(value, valuestr, i);
119        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
120        TEST_CHK(s == FDB_RESULT_SUCCESS);
121        TEST_CMP(value, value_out, valuelen);
122        fdb_free_block(value_out);
123
124        // metaonly by key
125        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
126        s = fdb_get_metaonly(db, doc);
127        TEST_CHK(s == FDB_RESULT_SUCCESS);
128        TEST_CMP(doc->key, key, doc->keylen);
129        TEST_CMP(doc->meta, meta, doc->metalen);
130        fdb_doc_free(doc);
131
132        // by seq
133        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
134        doc->seqnum = i+1;
135        s = fdb_get_byseq(db, doc);
136        TEST_CHK(s == FDB_RESULT_SUCCESS);
137        TEST_CMP(doc->key, key, doc->keylen);
138        TEST_CMP(doc->body, value, doc->bodylen);
139        fdb_doc_free(doc);
140
141        // metaonly by seq
142        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
143        doc->seqnum = i+1;
144        s = fdb_get_metaonly_byseq(db, doc);
145        TEST_CHK(s == FDB_RESULT_SUCCESS);
146        TEST_CMP(doc->key, key, doc->keylen);
147        TEST_CMP(doc->meta, meta, doc->metalen);
148        fdb_doc_free(doc);
149    }
150    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
151    TEST_CHK(s == FDB_RESULT_SUCCESS);
152
153    // info check
154    s = fdb_get_file_info(dbfile, &file_info);
155    TEST_CHK(s == FDB_RESULT_SUCCESS);
156    TEST_CHK(file_info.doc_count == (uint64_t)n);
157    TEST_CHK(file_info.num_kv_stores == 1);
158    s = fdb_get_kvs_info(db, &kvs_info);
159    TEST_CHK(s == FDB_RESULT_SUCCESS);
160    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
161
162    kvs_config.create_if_missing = false;
163    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
164    TEST_CHK(s != FDB_RESULT_SUCCESS); // must fail
165
166    kvs_config.create_if_missing = true;
167    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
168    TEST_CHK(s == FDB_RESULT_SUCCESS);
169
170    // insert using 'kv1' instance
171    for (i=0;i<n;++i){
172        sprintf(key, keystr, i);
173        sprintf(meta, metastr_kv, i);
174        sprintf(value, valuestr_kv, i);
175        fdb_doc_create(&doc, key, strlen(key)+1, meta,
176                           strlen(meta)+1, value, strlen(value)+1);
177        s = fdb_set(kv1, doc);
178        TEST_CHK(s == FDB_RESULT_SUCCESS);
179        fdb_doc_free(doc);
180    }
181
182    // retrieve from WAL
183    for (i=0;i<n;++i){
184        // by key
185        sprintf(key, keystr, i);
186        sprintf(meta, metastr_kv, i);
187        sprintf(value, valuestr_kv, i);
188        s = fdb_get_kv(kv1, key, strlen(key)+1, &value_out, &valuelen);
189        TEST_CHK(s == FDB_RESULT_SUCCESS);
190        TEST_CMP(value, value_out, valuelen);
191        fdb_free_block(value_out);
192
193        // metaonly by key
194        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
195        s = fdb_get_metaonly(kv1, doc);
196        TEST_CHK(s == FDB_RESULT_SUCCESS);
197        TEST_CMP(doc->key, key, doc->keylen);
198        TEST_CMP(doc->meta, meta, doc->metalen);
199        fdb_doc_free(doc);
200
201        // by seq
202        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
203        doc->seqnum = i+1;
204        s = fdb_get_byseq(kv1, doc);
205        TEST_CHK(s == FDB_RESULT_SUCCESS);
206        TEST_CMP(doc->key, key, doc->keylen);
207        TEST_CMP(doc->body, value, doc->bodylen);
208        fdb_doc_free(doc);
209
210        // metaonly by seq
211        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
212        doc->seqnum = i+1;
213        s = fdb_get_metaonly_byseq(kv1, doc);
214        TEST_CHK(s == FDB_RESULT_SUCCESS);
215        TEST_CMP(doc->key, key, doc->keylen);
216        TEST_CMP(doc->meta, meta, doc->metalen);
217        fdb_doc_free(doc);
218    }
219    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
220    TEST_CHK(s == FDB_RESULT_SUCCESS);
221
222    // retrieve from hb+trie
223    for (i=0;i<n;++i){
224        // ==== the default instance ====
225        // by key
226        sprintf(key, keystr, i);
227        sprintf(meta, metastr, i);
228        sprintf(value, valuestr, i);
229        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
230        TEST_CHK(s == FDB_RESULT_SUCCESS);
231        TEST_CMP(value, value_out, valuelen);
232        fdb_free_block(value_out);
233
234        // metaonly by key
235        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
236        s = fdb_get_metaonly(db, doc);
237        TEST_CHK(s == FDB_RESULT_SUCCESS);
238        TEST_CMP(doc->key, key, doc->keylen);
239        TEST_CMP(doc->meta, meta, doc->metalen);
240        fdb_doc_free(doc);
241
242        // by seq
243        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
244        doc->seqnum = i+1;
245        s = fdb_get_byseq(db, doc);
246        TEST_CHK(s == FDB_RESULT_SUCCESS);
247        TEST_CMP(doc->key, key, doc->keylen);
248        TEST_CMP(doc->body, value, doc->bodylen);
249        fdb_doc_free(doc);
250
251        // metaonly by seq
252        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
253        doc->seqnum = i+1;
254        s = fdb_get_metaonly_byseq(db, doc);
255        TEST_CHK(s == FDB_RESULT_SUCCESS);
256        TEST_CMP(doc->key, key, doc->keylen);
257        TEST_CMP(doc->meta, meta, doc->metalen);
258
259        // by offset
260        s = fdb_get_byoffset(db, doc);
261        TEST_CHK(s == FDB_RESULT_SUCCESS);
262        TEST_CMP(doc->key, key, doc->keylen);
263        TEST_CMP(doc->body, value, doc->bodylen);
264        fdb_doc_free(doc);
265
266        // ==== 'kv1' instance ====
267        // by key
268        sprintf(meta, metastr_kv, i);
269        sprintf(value, valuestr_kv, i);
270        s = fdb_get_kv(kv1, key, strlen(key)+1, &value_out, &valuelen);
271        TEST_CHK(s == FDB_RESULT_SUCCESS);
272        TEST_CMP(value, value_out, valuelen);
273        fdb_free_block(value_out);
274
275        // metaonly by key
276        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
277        s = fdb_get_metaonly(kv1, doc);
278        TEST_CHK(s == FDB_RESULT_SUCCESS);
279        TEST_CMP(doc->key, key, doc->keylen);
280        TEST_CMP(doc->meta, meta, doc->metalen);
281        fdb_doc_free(doc);
282
283        // by seq
284        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
285        doc->seqnum = i+1;
286        s = fdb_get_byseq(kv1, doc);
287        TEST_CHK(s == FDB_RESULT_SUCCESS);
288        TEST_CMP(doc->key, key, doc->keylen);
289        TEST_CMP(doc->body, value, doc->bodylen);
290        fdb_doc_free(doc);
291
292        // metaonly by seq
293        fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
294        doc->seqnum = i+1;
295        s = fdb_get_metaonly_byseq(kv1, doc);
296        TEST_CHK(s == FDB_RESULT_SUCCESS);
297        TEST_CMP(doc->key, key, doc->keylen);
298        TEST_CMP(doc->meta, meta, doc->metalen);
299
300        // by offset
301        s = fdb_get_byoffset(kv1, doc);
302        TEST_CHK(s == FDB_RESULT_SUCCESS);
303        TEST_CMP(doc->key, key, doc->keylen);
304        TEST_CMP(doc->body, value, doc->bodylen);
305        fdb_doc_free(doc);
306    }
307
308    // info check
309    s = fdb_get_file_info(dbfile, &file_info);
310    TEST_CHK(s == FDB_RESULT_SUCCESS);
311    TEST_CHK(file_info.doc_count == (uint64_t)n*2);
312    TEST_CHK(file_info.num_kv_stores == 2);
313    s = fdb_get_kvs_info(db, &kvs_info);
314    TEST_CHK(s == FDB_RESULT_SUCCESS);
315    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
316    s = fdb_get_kvs_info(kv1, &kvs_info);
317    TEST_CHK(s == FDB_RESULT_SUCCESS);
318    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
319
320    s = fdb_kvs_close(kv1);
321    TEST_CHK(s == FDB_RESULT_SUCCESS);
322    s = fdb_close(dbfile);
323    TEST_CHK(s == FDB_RESULT_SUCCESS);
324
325    if (opt & MULTI_KV_VAR_CMP) {
326        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
327                                2, kvs_names, functions);
328        TEST_CHK(s == FDB_RESULT_SUCCESS);
329    } else {
330        s = fdb_open(&dbfile, "./multi_kv_test", &config);
331        TEST_CHK(s == FDB_RESULT_SUCCESS);
332    }
333    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
334    TEST_CHK(s == FDB_RESULT_SUCCESS);
335    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
336    TEST_CHK(s == FDB_RESULT_SUCCESS);
337
338    // retrieve check after reopen
339    for (i=0;i<n;++i){
340        sprintf(key, keystr, i);
341        sprintf(value, valuestr, i);
342        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
343        TEST_CHK(s == FDB_RESULT_SUCCESS);
344        TEST_CMP(value, value_out, valuelen);
345        s = fdb_free_block(value_out);
346        TEST_CHK(s == FDB_RESULT_SUCCESS);
347
348        sprintf(value, valuestr_kv, i);
349        s = fdb_get_kv(kv1, key, strlen(key)+1, &value_out, &valuelen);
350        TEST_CHK(s == FDB_RESULT_SUCCESS);
351        TEST_CMP(value, value_out, valuelen);
352        s = fdb_free_block(value_out);
353        TEST_CHK(s == FDB_RESULT_SUCCESS);
354    }
355    // info check after reopen
356    s = fdb_get_file_info(dbfile, &file_info);
357    TEST_CHK(s == FDB_RESULT_SUCCESS);
358    TEST_CHK(file_info.doc_count == (uint64_t)n*2);
359    s = fdb_get_kvs_info(db, &kvs_info);
360    TEST_CHK(s == FDB_RESULT_SUCCESS);
361    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
362    s = fdb_get_kvs_info(kv1, &kvs_info);
363    TEST_CHK(s == FDB_RESULT_SUCCESS);
364    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
365
366    s = fdb_compact(dbfile, "./multi_kv_test2");
367    TEST_CHK(s == FDB_RESULT_SUCCESS);
368    // retrieve check after compaction
369    for (i=0;i<n;++i){
370        sprintf(key, keystr, i);
371        sprintf(value, valuestr, i);
372        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
373        TEST_CHK(s == FDB_RESULT_SUCCESS);
374        TEST_CMP(value, value_out, valuelen);
375        fdb_free_block(value_out);
376
377        sprintf(value, valuestr_kv, i);
378        s = fdb_get_kv(kv1, key, strlen(key)+1, &value_out, &valuelen);
379        TEST_CHK(s == FDB_RESULT_SUCCESS);
380        TEST_CMP(value, value_out, valuelen);
381        fdb_free_block(value_out);
382    }
383    // info check after compaction
384    s = fdb_get_file_info(dbfile, &file_info);
385    TEST_CHK(s == FDB_RESULT_SUCCESS);
386    TEST_CHK(file_info.doc_count == (uint64_t)n*2);
387    s = fdb_get_kvs_info(db, &kvs_info);
388    TEST_CHK(s == FDB_RESULT_SUCCESS);
389    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
390    s = fdb_get_kvs_info(kv1, &kvs_info);
391    TEST_CHK(s == FDB_RESULT_SUCCESS);
392    TEST_CHK(kvs_info.doc_count == (uint64_t)n);
393
394    // reopen using "default" KVS name
395    fdb_kvs_close(db);
396    s = fdb_kvs_open(dbfile, &db, "default", &kvs_config);
397    TEST_CHK(s == FDB_RESULT_SUCCESS);
398    for (i=0;i<n;++i){
399        sprintf(key, keystr, i);
400        sprintf(value, valuestr, i);
401        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
402        TEST_CHK(s == FDB_RESULT_SUCCESS);
403        TEST_CMP(value, value_out, valuelen);
404        fdb_free_block(value_out);
405    }
406
407    s = fdb_kvs_remove(dbfile, "kv1");
408    // must fail due to opened handle
409    TEST_CHK(s != FDB_RESULT_SUCCESS);
410
411    // Close "kv1" handle
412    s = fdb_kvs_close(kv1);
413    TEST_CHK(s == FDB_RESULT_SUCCESS);
414    // re-open with a new file handle
415    fdb_file_handle *fhandle;
416    if (opt & MULTI_KV_VAR_CMP) {
417        s = fdb_open_custom_cmp(&fhandle, "./multi_kv_test2", &config,
418                                2, kvs_names, functions);
419        TEST_CHK(s == FDB_RESULT_SUCCESS);
420    } else {
421        s = fdb_open(&fhandle, "./multi_kv_test2", &config);
422        TEST_CHK(s == FDB_RESULT_SUCCESS);
423    }
424    s = fdb_kvs_open(fhandle, &kv1, "kv1", &kvs_config);
425    TEST_CHK(s == FDB_RESULT_SUCCESS);
426    // Try to remove "kv1" again, but should fail
427    s = fdb_kvs_remove(dbfile, "kv1");
428    TEST_CHK(s == FDB_RESULT_KV_STORE_BUSY);
429
430    // closing super handles also closes all other sub-handles;
431    s = fdb_close(fhandle);
432    TEST_CHK(s == FDB_RESULT_SUCCESS);
433    s = fdb_close(dbfile);
434    TEST_CHK(s == FDB_RESULT_SUCCESS);
435
436    // re-open
437    if (opt & MULTI_KV_VAR_CMP) {
438        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test2", &config,
439                                2, kvs_names, functions);
440        TEST_CHK(s == FDB_RESULT_SUCCESS);
441    } else {
442        s = fdb_open(&dbfile, "./multi_kv_test2", &config);
443        TEST_CHK(s == FDB_RESULT_SUCCESS);
444    }
445
446    // remove "kv1" instance
447    s = fdb_kvs_remove(dbfile, "kv1");
448    TEST_CHK(s == FDB_RESULT_SUCCESS);
449    s = fdb_kvs_open(dbfile, &db, "default", &kvs_config);
450    TEST_CHK(s == FDB_RESULT_SUCCESS);
451    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
452    TEST_CHK(s == FDB_RESULT_SUCCESS);
453    for (i=0;i<n;++i){
454        sprintf(key, keystr, i);
455        sprintf(value, valuestr, i);
456        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
457        TEST_CHK(s == FDB_RESULT_SUCCESS);
458        TEST_CMP(value, value_out, valuelen);
459        fdb_free_block(value_out);
460
461        s = fdb_get_kv(kv1, key, strlen(key)+1, &value_out, &valuelen);
462        TEST_CHK(s != FDB_RESULT_SUCCESS);
463    }
464    s = fdb_kvs_close(db);
465    TEST_CHK(s == FDB_RESULT_SUCCESS);
466    s = fdb_kvs_close(kv1);
467    TEST_CHK(s == FDB_RESULT_SUCCESS);
468
469    // remove "default" instance
470    s = fdb_kvs_remove(dbfile, "default");
471    TEST_CHK(s == FDB_RESULT_SUCCESS);
472    s = fdb_kvs_open(dbfile, &db, "default", &kvs_config);
473    TEST_CHK(s == FDB_RESULT_SUCCESS);
474    for (i=0;i<n;++i){
475        sprintf(key, keystr, i);
476        s = fdb_get_kv(db, key, strlen(key)+1, &value_out, &valuelen);
477        TEST_CHK(s != FDB_RESULT_SUCCESS);
478    }
479    s = fdb_kvs_close(db);
480    TEST_CHK(s == FDB_RESULT_SUCCESS);
481
482    // remove the empty "kv1" instance
483    s = fdb_kvs_remove(dbfile, "kv1");
484    TEST_CHK(s == FDB_RESULT_SUCCESS);
485
486    s = fdb_close(dbfile);
487    TEST_CHK(s == FDB_RESULT_SUCCESS);
488
489    s = fdb_shutdown();
490    TEST_CHK(s == FDB_RESULT_SUCCESS);
491    memleak_end();
492
493    if (opt & MULTI_KV_VAR_CMP) {
494        TEST_RESULT("multiple KV instances basic test "
495                    "(custom key order)");
496    } else {
497        TEST_RESULT("multiple KV instances basic test");
498    }
499}
500
501void multi_kv_iterator_key_test(uint8_t opt, size_t chunksize)
502{
503    TEST_INIT();
504
505    int n = 100;
506    int i, r;
507    char key[256], value[256];
508    char keystr[] = "key%06d";
509    char valuestr[] = "value%08d(%s)";
510    fdb_file_handle *dbfile;
511    fdb_kvs_handle *db, *kv1, *kv2;
512    fdb_config config;
513    fdb_kvs_config kvs_config;
514    fdb_doc *doc = NULL;
515    fdb_iterator *it;
516    fdb_status s;
517
518    sprintf(value, SHELL_DEL" multi_kv_test*");
519    r = system(value);
520    (void)r;
521
522    memleak_start();
523
524    config = fdb_get_default_config();
525    kvs_config = fdb_get_default_kvs_config();
526    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
527    config.chunksize = chunksize;
528    config.multi_kv_instances = true;
529    config.wal_threshold = 1000;
530    config.buffercache_size = 0;
531
532    s = fdb_open(&dbfile, "./multi_kv_test", &config);
533    TEST_CHK(s == FDB_RESULT_SUCCESS);
534    if (opt & MULTI_KV_VAR_CMP) {
535        kvs_config.custom_cmp = _multi_kv_test_keycmp;
536    }
537    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
538    TEST_CHK(s == FDB_RESULT_SUCCESS);
539    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
540    TEST_CHK(s == FDB_RESULT_SUCCESS);
541    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
542    TEST_CHK(s == FDB_RESULT_SUCCESS);
543
544    for (i=0;i<n;i+=2) {
545        sprintf(key, keystr, i);
546        sprintf(value, valuestr, i, "default");
547        s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
548        TEST_CHK(s == FDB_RESULT_SUCCESS);
549        sprintf(value, valuestr, i, "kv1");
550        s = fdb_set_kv(kv1, key, strlen(key)+1, value, strlen(value)+1);
551        TEST_CHK(s == FDB_RESULT_SUCCESS);
552        sprintf(value, valuestr, i, "kv2");
553        s = fdb_set_kv(kv2, key, strlen(key)+1, value, strlen(value)+1);
554        TEST_CHK(s == FDB_RESULT_SUCCESS);
555    }
556    fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
557
558    for (i=1;i<n;i+=2) {
559        sprintf(key, keystr, i);
560        sprintf(value, valuestr, i, "default");
561        s = fdb_set_kv(db, key, strlen(key)+1, value, strlen(value)+1);
562        TEST_CHK(s == FDB_RESULT_SUCCESS);
563        sprintf(value, valuestr, i, "kv1");
564        s = fdb_set_kv(kv1, key, strlen(key)+1, value, strlen(value)+1);
565        TEST_CHK(s == FDB_RESULT_SUCCESS);
566        sprintf(value, valuestr, i, "kv2");
567        s = fdb_set_kv(kv2, key, strlen(key)+1, value, strlen(value)+1);
568        TEST_CHK(s == FDB_RESULT_SUCCESS);
569    }
570    fdb_commit(dbfile, FDB_COMMIT_NORMAL);
571
572    // iterate on default KV instance
573    i = 0;
574    s = fdb_iterator_init(db, &it, NULL, 0, NULL, 0, FDB_ITR_NONE);
575    TEST_CHK(s == FDB_RESULT_SUCCESS);
576    do {
577        s = fdb_iterator_get(it, &doc);
578        TEST_CHK(s == FDB_RESULT_SUCCESS);
579        sprintf(key, keystr, i);
580        sprintf(value, valuestr, i, "default");
581        TEST_CMP(doc->key, key, doc->keylen);
582        TEST_CMP(doc->body, value, doc->bodylen);
583        r = ((i%2 == 0)?(i/2):(50+i/2)) +1;
584        TEST_CHK(doc->seqnum == (fdb_seqnum_t)r);
585        fdb_doc_free(doc);
586        doc = NULL;
587        i++;
588    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
589    TEST_CHK(i == n);
590    fdb_iterator_close(it);
591
592    // iterate in kv1 instance
593    i = 0;
594    s = fdb_iterator_init(kv1, &it, NULL, 0, NULL, 0, FDB_ITR_NONE);
595    TEST_CHK(s == FDB_RESULT_SUCCESS);
596    do {
597        s = fdb_iterator_get(it, &doc);
598        TEST_CHK(s == FDB_RESULT_SUCCESS);
599        sprintf(key, keystr, i);
600        sprintf(value, valuestr, i, "kv1");
601        TEST_CMP(doc->key, key, doc->keylen);
602        TEST_CMP(doc->body, value, doc->bodylen);
603        r = ((i%2 == 0)?(i/2):(50+i/2)) +1;
604        TEST_CHK(doc->seqnum == (fdb_seqnum_t)r);
605        fdb_doc_free(doc);
606        doc = NULL;
607        i++;
608    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
609    TEST_CHK(i == n);
610    // reverse iterate in kv1 instance
611    TEST_CHK(fdb_iterator_prev(it) == FDB_RESULT_SUCCESS);
612    do {
613        s = fdb_iterator_get(it, &doc);
614        TEST_CHK(s == FDB_RESULT_SUCCESS);
615        i--;
616        sprintf(key, keystr, i);
617        sprintf(value, valuestr, i, "kv1");
618        TEST_CMP(doc->key, key, doc->keylen);
619        TEST_CMP(doc->body, value, doc->bodylen);
620        r = ((i%2 == 0)?(i/2):(50+i/2)) +1;
621        TEST_CHK(doc->seqnum == (fdb_seqnum_t)r);
622        fdb_doc_free(doc);
623        doc = NULL;
624    } while (fdb_iterator_prev(it) == FDB_RESULT_SUCCESS);
625    TEST_CHK(i == 0);
626    fdb_iterator_close(it);
627
628    // iterate in kv2 instance
629    i = 0;
630    s = fdb_iterator_init(kv2, &it, NULL, 0, NULL, 0, FDB_ITR_NONE);
631    TEST_CHK(s == FDB_RESULT_SUCCESS);
632    do {
633        s = fdb_iterator_get(it, &doc);
634        TEST_CHK(s == FDB_RESULT_SUCCESS);
635        sprintf(key, keystr, i);
636        sprintf(value, valuestr, i, "kv2");
637        TEST_CMP(doc->key, key, doc->keylen);
638        TEST_CMP(doc->body, value, doc->bodylen);
639        fdb_doc_free(doc);
640        doc = NULL;
641        i++;
642    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
643    TEST_CHK(i == n);
644    fdb_iterator_close(it);
645
646    // partial iterate in kv1 instance
647    i = 40;
648    char key2[256];
649    sprintf(key, keystr, 40);
650    sprintf(key2, keystr, 59);
651    s = fdb_iterator_init(kv1, &it, key, strlen(key)+1, key2, strlen(key2)+1,
652                          FDB_ITR_NONE);
653    TEST_CHK(s == FDB_RESULT_SUCCESS);
654    do {
655        s = fdb_iterator_get(it, &doc);
656        TEST_CHK(s == FDB_RESULT_SUCCESS);
657        sprintf(key, keystr, i);
658        sprintf(value, valuestr, i, "kv1");
659        TEST_CMP(doc->key, key, doc->keylen);
660        TEST_CMP(doc->body, value, doc->bodylen);
661        fdb_doc_free(doc);
662        doc = NULL;
663        i++;
664    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
665    TEST_CHK(i == 60);
666    fdb_iterator_close(it);
667
668    s = fdb_kvs_close(kv1);
669    TEST_CHK(s == FDB_RESULT_SUCCESS);
670    s = fdb_kvs_close(kv2);
671    TEST_CHK(s == FDB_RESULT_SUCCESS);
672    s = fdb_close(dbfile);
673    TEST_CHK(s == FDB_RESULT_SUCCESS);
674    s = fdb_shutdown();
675    TEST_CHK(s == FDB_RESULT_SUCCESS);
676
677    memleak_end();
678
679    if (opt & MULTI_KV_VAR_CMP) {
680        TEST_RESULT("multiple KV instances iterator test "
681                    "(custom key order)");
682    } else {
683        TEST_RESULT("multiple KV instances iterator test");
684    }
685}
686
687void multi_kv_iterator_seq_test(uint8_t opt, size_t chunksize)
688{
689    TEST_INIT();
690
691    int n = 100;
692    int i, r;
693    char key[256], value[256];
694    char keyBuf[256], valueBuf[256];
695    char keystr[] = "key%06d";
696    char valuestr[] = "value%08d(%s)";
697    fdb_file_handle *dbfile;
698    fdb_kvs_handle *db, *kv1, *kv2;
699    fdb_config config;
700    fdb_kvs_config kvs_config;
701    fdb_doc *doc;
702    fdb_iterator *it;
703    fdb_status s;
704    fdb_seqnum_t seqnum;
705
706    sprintf(value, SHELL_DEL" multi_kv_test*");
707    r = system(value);
708    (void)r;
709
710    memleak_start();
711
712    config = fdb_get_default_config();
713    kvs_config = fdb_get_default_kvs_config();
714    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
715    config.chunksize = chunksize;
716    config.multi_kv_instances = true;
717    config.wal_threshold = 1000;
718    config.buffercache_size = 0;
719
720    s = fdb_open(&dbfile, "./multi_kv_test", &config);
721    TEST_CHK(s == FDB_RESULT_SUCCESS);
722    if (opt & MULTI_KV_VAR_CMP) {
723        kvs_config.custom_cmp = _multi_kv_test_keycmp;
724    }
725    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
726    TEST_CHK(s == FDB_RESULT_SUCCESS);
727    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
728    TEST_CHK(s == FDB_RESULT_SUCCESS);
729    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
730    TEST_CHK(s == FDB_RESULT_SUCCESS);
731
732    // write documents first time
733    for (i=0;i<n;++i){
734        sprintf(key, keystr, i);
735        sprintf(value, valuestr, i, "default");
736        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
737        s = fdb_set(db, doc);
738        TEST_CHK(s == FDB_RESULT_SUCCESS);
739        fdb_doc_free(doc);
740        sprintf(value, valuestr, i, "kv1");
741        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
742        s = fdb_set(kv1, doc);
743        TEST_CHK(s == FDB_RESULT_SUCCESS);
744        fdb_doc_free(doc);
745        sprintf(value, valuestr, i, "kv2");
746        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
747        s = fdb_set(kv2, doc);
748        TEST_CHK(s == FDB_RESULT_SUCCESS);
749        fdb_doc_free(doc);
750    }
751    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
752    TEST_CHK(s == FDB_RESULT_SUCCESS);
753
754    // re-write documents
755    for (i=0;i<n;++i){
756        sprintf(key, keystr, i);
757        sprintf(value, valuestr, i, "default_second");
758        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
759        s = fdb_set(db, doc);
760        TEST_CHK(s == FDB_RESULT_SUCCESS);
761        fdb_doc_free(doc);
762        sprintf(value, valuestr, i, "kv1_second");
763        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
764        s = fdb_set(kv1, doc);
765        TEST_CHK(s == FDB_RESULT_SUCCESS);
766        fdb_doc_free(doc);
767        sprintf(value, valuestr, i, "kv2_second");
768        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
769        s = fdb_set(kv2, doc);
770        TEST_CHK(s == FDB_RESULT_SUCCESS);
771        fdb_doc_free(doc);
772    }
773    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
774    TEST_CHK(s == FDB_RESULT_SUCCESS);
775
776    // write third time (even number docs only)
777    for (i=0;i<n;i+=2){
778        sprintf(key, keystr, i);
779        sprintf(value, valuestr, i, "default_third");
780        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
781        s = fdb_set(db, doc);
782        TEST_CHK(s == FDB_RESULT_SUCCESS);
783        fdb_doc_free(doc);
784        sprintf(value, valuestr, i, "kv1_third");
785        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
786        s = fdb_set(kv1, doc);
787        TEST_CHK(s == FDB_RESULT_SUCCESS);
788        fdb_doc_free(doc);
789        sprintf(value, valuestr, i, "kv2_third");
790        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
791        s = fdb_set(kv2, doc);
792        TEST_CHK(s == FDB_RESULT_SUCCESS);
793        fdb_doc_free(doc);
794    }
795    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
796    TEST_CHK(s == FDB_RESULT_SUCCESS);
797
798    // pre-allocate memory and re-use it for the iterator return document
799    s = fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
800    TEST_CHK(s == FDB_RESULT_SUCCESS);
801    doc->key = &keyBuf[0];
802    doc->body = &valueBuf[0];
803
804    // iterate in default KV instance
805    i = 1;
806    s = fdb_iterator_sequence_init(db, &it, 0, 0, FDB_ITR_NONE);
807    TEST_CHK(s == FDB_RESULT_SUCCESS);
808    while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS) {
809        s = fdb_iterator_get(it, &doc);
810        TEST_CHK(s == FDB_RESULT_SUCCESS);
811        i++;
812    }
813    TEST_CHK(i == n);
814    fdb_iterator_close(it);
815
816    // iterate in KV1
817    i = 0;
818    s = fdb_iterator_sequence_init(kv1, &it, 0, 0, FDB_ITR_NONE);
819    TEST_CHK(s == FDB_RESULT_SUCCESS);
820    do {
821        s = fdb_iterator_get(it, &doc);
822        TEST_CHK(s == FDB_RESULT_SUCCESS);
823        if (i < 50) {
824            r = i*2 + 1;
825            seqnum = 100 + (i+1)*2;
826            sprintf(value, valuestr, r, "kv1_second");
827        } else {
828            r = (i-50)*2;
829            seqnum = 151 + i;
830            sprintf(value, valuestr, r, "kv1_third");
831        }
832        sprintf(key, keystr, r);
833        TEST_CMP(key, doc->key, doc->keylen);
834        TEST_CMP(value, doc->body, doc->bodylen);
835        TEST_CHK(doc->seqnum == seqnum);
836        i++;
837    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
838    TEST_CHK(i == n);
839    // reverse iterate in KV1
840    TEST_CHK(fdb_iterator_prev(it) == FDB_RESULT_SUCCESS);
841    do {
842        s = fdb_iterator_get(it, &doc);
843        TEST_CHK(s == FDB_RESULT_SUCCESS);
844        i--;
845        if (i < 50) {
846            r = i*2 + 1;
847            seqnum = 100 + (i+1)*2;
848            sprintf(value, valuestr, r, "kv1_second");
849        } else {
850            r = (i-50)*2;
851            seqnum = 151 + i;
852            sprintf(value, valuestr, r, "kv1_third");
853        }
854        sprintf(key, keystr, r);
855        TEST_CMP(key, doc->key, doc->keylen);
856        TEST_CMP(value, doc->body, doc->bodylen);
857        TEST_CHK(doc->seqnum == seqnum);
858    } while (fdb_iterator_prev(it) == FDB_RESULT_SUCCESS);
859    TEST_CHK(i == 0);
860    fdb_iterator_close(it);
861
862    // iterate in KV2
863    i = 0;
864    s = fdb_iterator_sequence_init(kv2, &it, 0, 0, FDB_ITR_NONE);
865    TEST_CHK(s == FDB_RESULT_SUCCESS);
866    do {
867        s = fdb_iterator_get(it, &doc);
868        TEST_CHK(s == FDB_RESULT_SUCCESS);
869        if (i < 50) {
870            r = i*2 + 1;
871            seqnum = 100 + (i+1)*2;
872            sprintf(value, valuestr, r, "kv2_second");
873        } else {
874            r = (i-50)*2;
875            seqnum = 151 + i;
876            sprintf(value, valuestr, r, "kv2_third");
877        }
878        (void)seqnum;
879        sprintf(key, keystr, r);
880        i++;
881    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
882    TEST_CHK(i == n);
883    fdb_iterator_close(it);
884
885    // partial iterate in KV1
886    i = 0;
887    s = fdb_iterator_sequence_init(kv1, &it, 150, 220, FDB_ITR_NONE);
888    TEST_CHK(s == FDB_RESULT_SUCCESS);
889    do {
890        s = fdb_iterator_get(it, &doc);
891        TEST_CHK(s == FDB_RESULT_SUCCESS);
892        //printf("%d %s %s %d\n", i, (char*)doc->key, (char*)doc->body, (int)doc->seqnum);
893        if (i<26) {
894            r = 49 + i*2;
895            seqnum = i*2 + 150;
896            sprintf(value, valuestr, r, "kv1_second");
897        } else {
898            r = (i-26)*2;
899            seqnum = 201 + (i-26);
900            sprintf(value, valuestr, r, "kv1_third");
901        }
902        (void)seqnum;
903        i++;
904    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
905    TEST_CHK(i == 71);
906    fdb_iterator_close(it);
907
908    s = fdb_kvs_close(kv1);
909    TEST_CHK(s == FDB_RESULT_SUCCESS);
910    s = fdb_kvs_close(kv2);
911    TEST_CHK(s == FDB_RESULT_SUCCESS);
912    s = fdb_close(dbfile);
913    TEST_CHK(s == FDB_RESULT_SUCCESS);
914    s = fdb_shutdown();
915    TEST_CHK(s == FDB_RESULT_SUCCESS);
916
917    // free up the pre-allocated buffer for iterator return document
918    doc->key = NULL;
919    doc->body = NULL;
920    s = fdb_doc_free(doc);
921    TEST_CHK(s == FDB_RESULT_SUCCESS);
922
923    memleak_end();
924
925    if (opt & MULTI_KV_VAR_CMP) {
926        TEST_RESULT("multiple KV instances sequence iterator test "
927                    "(custom key order)");
928    } else {
929        TEST_RESULT("multiple KV instances sequence iterator test");
930    }
931}
932
933void multi_kv_txn_test(uint8_t opt, size_t chunksize)
934{
935    TEST_INIT();
936
937    int n = 100;
938    int i, r;
939    char key[256], value[256];
940    char keystr[] = "key%06d";
941    char valuestr[] = "value%08d(%s)";
942    fdb_file_handle *dbfile, *dbfile_txn1;
943    fdb_kvs_handle *db, *kv1, *kv2;
944    fdb_kvs_handle *txn1, *txn1_kv1, *txn1_kv2;
945    fdb_config config;
946    fdb_kvs_config kvs_config;
947    fdb_doc *doc;
948    fdb_status s;
949
950    char *kvs_names[] = {(char*)"default", (char*)"kv1", (char*)"kv2"};
951    fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp,
952                                           _multi_kv_test_keycmp,
953                                           _multi_kv_test_keycmp};
954
955    sprintf(value, SHELL_DEL" multi_kv_test*");
956    r = system(value);
957    (void)r;
958
959    memleak_start();
960
961    config = fdb_get_default_config();
962    kvs_config = fdb_get_default_kvs_config();
963    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
964    config.chunksize = chunksize;
965    config.multi_kv_instances = true;
966    config.wal_threshold = 1000;
967    config.buffercache_size = 0;
968
969    s = fdb_open(&dbfile, "./multi_kv_test", &config);
970    TEST_CHK(s == FDB_RESULT_SUCCESS);
971    if (opt & MULTI_KV_VAR_CMP) {
972        kvs_config.custom_cmp = _multi_kv_test_keycmp;
973    }
974    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
975    TEST_CHK(s == FDB_RESULT_SUCCESS);
976    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
977    TEST_CHK(s == FDB_RESULT_SUCCESS);
978    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
979    TEST_CHK(s == FDB_RESULT_SUCCESS);
980
981    // write documents first time
982    for (i=0;i<n;++i){
983        sprintf(key, keystr, i);
984        sprintf(value, valuestr, i, "default");
985        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
986        s = fdb_set(db, doc);
987        TEST_CHK(s == FDB_RESULT_SUCCESS);
988        fdb_doc_free(doc);
989        sprintf(value, valuestr, i, "kv1");
990        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
991        s = fdb_set(kv1, doc);
992        TEST_CHK(s == FDB_RESULT_SUCCESS);
993        fdb_doc_free(doc);
994        sprintf(value, valuestr, i, "kv2");
995        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
996        s = fdb_set(kv2, doc);
997        TEST_CHK(s == FDB_RESULT_SUCCESS);
998        fdb_doc_free(doc);
999    }
1000    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1001    TEST_CHK(s == FDB_RESULT_SUCCESS);
1002
1003    // begin a transaction
1004    if (opt & MULTI_KV_VAR_CMP) {
1005        s = fdb_open_custom_cmp(&dbfile_txn1, "./multi_kv_test", &config,
1006                                3, kvs_names, functions);
1007        TEST_CHK(s == FDB_RESULT_SUCCESS);
1008    } else {
1009        s = fdb_open(&dbfile_txn1, "./multi_kv_test", &config);
1010        TEST_CHK(s == FDB_RESULT_SUCCESS);
1011    }
1012    s = fdb_kvs_open(dbfile_txn1, &txn1, NULL, &kvs_config);
1013    TEST_CHK(s == FDB_RESULT_SUCCESS);
1014    s = fdb_kvs_open(dbfile_txn1, &txn1_kv1, "kv1", &kvs_config);
1015    TEST_CHK(s == FDB_RESULT_SUCCESS);
1016    s = fdb_kvs_open(dbfile_txn1, &txn1_kv2, "kv2", &kvs_config);
1017    TEST_CHK(s == FDB_RESULT_SUCCESS);
1018    s = fdb_begin_transaction(dbfile_txn1, FDB_ISOLATION_READ_COMMITTED);
1019    TEST_CHK(s == FDB_RESULT_SUCCESS);
1020
1021    for (i=0;i<n;++i){
1022        sprintf(key, keystr, i);
1023        sprintf(value, valuestr, i, "default(txn)");
1024        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1025        s = fdb_set(txn1, doc);
1026        TEST_CHK(s == FDB_RESULT_SUCCESS);
1027        fdb_doc_free(doc);
1028        sprintf(value, valuestr, i, "kv1(txn)");
1029        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1030        s = fdb_set(txn1_kv1, doc);
1031        TEST_CHK(s == FDB_RESULT_SUCCESS);
1032        fdb_doc_free(doc);
1033        sprintf(value, valuestr, i, "kv2(txn)");
1034        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1035        s = fdb_set(txn1_kv2, doc);
1036        TEST_CHK(s == FDB_RESULT_SUCCESS);
1037        fdb_doc_free(doc);
1038    }
1039
1040    // retrieve before commit (dirty read through the transaction)
1041    for (i=0;i<n;++i){
1042        sprintf(key, keystr, i);
1043        sprintf(value, valuestr, i, "default(txn)");
1044        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1045        s = fdb_get(txn1, doc);
1046        TEST_CHK(s == FDB_RESULT_SUCCESS);
1047        TEST_CMP(value, doc->body, doc->bodylen);
1048        fdb_doc_free(doc);
1049        TEST_CHK(s == FDB_RESULT_SUCCESS);
1050        sprintf(value, valuestr, i, "kv1(txn)");
1051        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1052        s = fdb_get(txn1_kv1, doc);
1053        TEST_CHK(s == FDB_RESULT_SUCCESS);
1054        TEST_CMP(value, doc->body, doc->bodylen);
1055        fdb_doc_free(doc);
1056        sprintf(value, valuestr, i, "kv2(txn)");
1057        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1058        s = fdb_get(txn1_kv2, doc);
1059        TEST_CHK(s == FDB_RESULT_SUCCESS);
1060        TEST_CMP(value, doc->body, doc->bodylen);
1061        fdb_doc_free(doc);
1062    }
1063
1064    // retrieve before commit (isolation test)
1065    for (i=0;i<n;++i){
1066        sprintf(key, keystr, i);
1067        sprintf(value, valuestr, i, "default");
1068        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1069        s = fdb_get(db, doc);
1070        TEST_CHK(s == FDB_RESULT_SUCCESS);
1071        TEST_CMP(value, doc->body, doc->bodylen);
1072        fdb_doc_free(doc);
1073        sprintf(value, valuestr, i, "kv1");
1074        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1075        s = fdb_get(kv1, doc);
1076        TEST_CHK(s == FDB_RESULT_SUCCESS);
1077        TEST_CMP(value, doc->body, doc->bodylen);
1078        fdb_doc_free(doc);
1079        sprintf(value, valuestr, i, "kv2");
1080        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1081        s = fdb_get(kv2, doc);
1082        TEST_CHK(s == FDB_RESULT_SUCCESS);
1083        TEST_CMP(value, doc->body, doc->bodylen);
1084        fdb_doc_free(doc);
1085    }
1086
1087    s = fdb_end_transaction(dbfile_txn1, FDB_COMMIT_NORMAL);
1088    TEST_CHK(s == FDB_RESULT_SUCCESS);
1089
1090    // retrieve after commit (through the transaction)
1091    for (i=0;i<n;++i){
1092        sprintf(key, keystr, i);
1093        sprintf(value, valuestr, i, "default(txn)");
1094        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1095        s = fdb_get(txn1, doc);
1096        TEST_CHK(s == FDB_RESULT_SUCCESS);
1097        TEST_CMP(value, doc->body, doc->bodylen);
1098        fdb_doc_free(doc);
1099        sprintf(value, valuestr, i, "kv1(txn)");
1100        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1101        s = fdb_get(txn1_kv1, doc);
1102        TEST_CHK(s == FDB_RESULT_SUCCESS);
1103        TEST_CMP(value, doc->body, doc->bodylen);
1104        fdb_doc_free(doc);
1105        sprintf(value, valuestr, i, "kv2(txn)");
1106        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1107        s = fdb_get(txn1_kv2, doc);
1108        TEST_CHK(s == FDB_RESULT_SUCCESS);
1109        TEST_CMP(value, doc->body, doc->bodylen);
1110        fdb_doc_free(doc);
1111    }
1112
1113    // retrieve after commit (isolation test)
1114    for (i=0;i<n;++i){
1115        sprintf(key, keystr, i);
1116        sprintf(value, valuestr, i, "default(txn)");
1117        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1118        s = fdb_get(db, doc);
1119        TEST_CHK(s == FDB_RESULT_SUCCESS);
1120        TEST_CMP(value, doc->body, doc->bodylen);
1121        fdb_doc_free(doc);
1122        sprintf(value, valuestr, i, "kv1(txn)");
1123        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1124        s = fdb_get(kv1, doc);
1125        TEST_CHK(s == FDB_RESULT_SUCCESS);
1126        TEST_CMP(value, doc->body, doc->bodylen);
1127        fdb_doc_free(doc);
1128        sprintf(value, valuestr, i, "kv2(txn)");
1129        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1130        s = fdb_get(kv2, doc);
1131        TEST_CHK(s == FDB_RESULT_SUCCESS);
1132        TEST_CMP(value, doc->body, doc->bodylen);
1133        fdb_doc_free(doc);
1134    }
1135
1136    // reopen
1137    s = fdb_kvs_close(txn1_kv1);
1138    TEST_CHK(s == FDB_RESULT_SUCCESS);
1139    s = fdb_kvs_close(txn1_kv2);
1140    TEST_CHK(s == FDB_RESULT_SUCCESS);
1141    s = fdb_close(dbfile_txn1);
1142    TEST_CHK(s == FDB_RESULT_SUCCESS);
1143    s = fdb_kvs_close(kv1);
1144    TEST_CHK(s == FDB_RESULT_SUCCESS);
1145    s = fdb_kvs_close(kv2);
1146    TEST_CHK(s == FDB_RESULT_SUCCESS);
1147    s = fdb_close(dbfile);
1148    TEST_CHK(s == FDB_RESULT_SUCCESS);
1149
1150    if (opt & MULTI_KV_VAR_CMP) {
1151        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1152                                3, kvs_names, functions);
1153        TEST_CHK(s == FDB_RESULT_SUCCESS);
1154    } else {
1155        s = fdb_open(&dbfile, "./multi_kv_test", &config);
1156        TEST_CHK(s == FDB_RESULT_SUCCESS);
1157    }
1158    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1159    TEST_CHK(s == FDB_RESULT_SUCCESS);
1160    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1161    TEST_CHK(s == FDB_RESULT_SUCCESS);
1162    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1163    TEST_CHK(s == FDB_RESULT_SUCCESS);
1164
1165    // retrieve after reopen
1166    for (i=0;i<n;++i){
1167        sprintf(key, keystr, i);
1168        sprintf(value, valuestr, i, "default(txn)");
1169        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1170        s = fdb_get(db, doc);
1171        TEST_CHK(s == FDB_RESULT_SUCCESS);
1172        TEST_CMP(value, doc->body, doc->bodylen);
1173        fdb_doc_free(doc);
1174        sprintf(value, valuestr, i, "kv1(txn)");
1175        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1176        s = fdb_get(kv1, doc);
1177        TEST_CHK(s == FDB_RESULT_SUCCESS);
1178        TEST_CMP(value, doc->body, doc->bodylen);
1179        fdb_doc_free(doc);
1180        sprintf(value, valuestr, i, "kv2(txn)");
1181        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1182        s = fdb_get(kv2, doc);
1183        TEST_CHK(s == FDB_RESULT_SUCCESS);
1184        TEST_CMP(value, doc->body, doc->bodylen);
1185        fdb_doc_free(doc);
1186    }
1187
1188    // begin a transaction
1189    if (opt & MULTI_KV_VAR_CMP) {
1190        s = fdb_open_custom_cmp(&dbfile_txn1, "./multi_kv_test", &config,
1191                                3, kvs_names, functions);
1192        TEST_CHK(s == FDB_RESULT_SUCCESS);
1193    } else {
1194        s = fdb_open(&dbfile_txn1, "./multi_kv_test", &config);
1195        TEST_CHK(s == FDB_RESULT_SUCCESS);
1196    }
1197    s = fdb_kvs_open(dbfile_txn1, &txn1, NULL, &kvs_config);
1198    TEST_CHK(s == FDB_RESULT_SUCCESS);
1199    s = fdb_kvs_open(dbfile_txn1, &txn1_kv1, "kv1", &kvs_config);
1200    TEST_CHK(s == FDB_RESULT_SUCCESS);
1201    s = fdb_kvs_open(dbfile_txn1, &txn1_kv2, "kv2", &kvs_config);
1202    TEST_CHK(s == FDB_RESULT_SUCCESS);
1203    s = fdb_begin_transaction(dbfile_txn1, FDB_ISOLATION_READ_COMMITTED);
1204    TEST_CHK(s == FDB_RESULT_SUCCESS);
1205
1206    for (i=0;i<n;++i){
1207        sprintf(key, keystr, i);
1208        sprintf(value, valuestr, i, "default(txn_abort)");
1209        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1210        s = fdb_set(txn1, doc);
1211        TEST_CHK(s == FDB_RESULT_SUCCESS);
1212        fdb_doc_free(doc);
1213        sprintf(value, valuestr, i, "kv1(txn_abort)");
1214        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1215        s = fdb_set(txn1_kv1, doc);
1216        TEST_CHK(s == FDB_RESULT_SUCCESS);
1217        fdb_doc_free(doc);
1218        sprintf(value, valuestr, i, "kv2(txn_abort)");
1219        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1220        s = fdb_set(txn1_kv2, doc);
1221        TEST_CHK(s == FDB_RESULT_SUCCESS);
1222        fdb_doc_free(doc);
1223    }
1224
1225    // abort the transaction
1226    s = fdb_abort_transaction(dbfile_txn1);
1227    TEST_CHK(s == FDB_RESULT_SUCCESS);
1228
1229    // reopen
1230    s = fdb_kvs_close(txn1_kv1);
1231    TEST_CHK(s == FDB_RESULT_SUCCESS);
1232    s = fdb_kvs_close(txn1_kv2);
1233    TEST_CHK(s == FDB_RESULT_SUCCESS);
1234    s = fdb_close(dbfile_txn1);
1235    TEST_CHK(s == FDB_RESULT_SUCCESS);
1236    s = fdb_kvs_close(kv1);
1237    TEST_CHK(s == FDB_RESULT_SUCCESS);
1238    s = fdb_kvs_close(kv2);
1239    TEST_CHK(s == FDB_RESULT_SUCCESS);
1240    s = fdb_close(dbfile);
1241    TEST_CHK(s == FDB_RESULT_SUCCESS);
1242
1243    if (opt & MULTI_KV_VAR_CMP) {
1244        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1245                                3, kvs_names, functions);
1246        TEST_CHK(s == FDB_RESULT_SUCCESS);
1247    } else {
1248        s = fdb_open(&dbfile, "./multi_kv_test", &config);
1249        TEST_CHK(s == FDB_RESULT_SUCCESS);
1250    }
1251    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1252    TEST_CHK(s == FDB_RESULT_SUCCESS);
1253    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1254    TEST_CHK(s == FDB_RESULT_SUCCESS);
1255    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1256    TEST_CHK(s == FDB_RESULT_SUCCESS);
1257
1258    // retrieve after reopen
1259    for (i=0;i<n;++i){
1260        sprintf(key, keystr, i);
1261        sprintf(value, valuestr, i, "default(txn)");
1262        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1263        s = fdb_get(db, doc);
1264        TEST_CHK(s == FDB_RESULT_SUCCESS);
1265        TEST_CMP(value, doc->body, doc->bodylen);
1266        fdb_doc_free(doc);
1267        sprintf(value, valuestr, i, "kv1(txn)");
1268        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1269        s = fdb_get(kv1, doc);
1270        TEST_CHK(s == FDB_RESULT_SUCCESS);
1271        TEST_CMP(value, doc->body, doc->bodylen);
1272        fdb_doc_free(doc);
1273        sprintf(value, valuestr, i, "kv2(txn)");
1274        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1275        s = fdb_get(kv2, doc);
1276        TEST_CHK(s == FDB_RESULT_SUCCESS);
1277        TEST_CMP(value, doc->body, doc->bodylen);
1278        fdb_doc_free(doc);
1279    }
1280
1281    // get KVS names
1282    fdb_kvs_name_list kvs_name_list;
1283    s = fdb_get_kvs_name_list(dbfile, &kvs_name_list);
1284    TEST_CHK(s == FDB_RESULT_SUCCESS);
1285    TEST_CHK(kvs_name_list.num_kvs_names == 3);
1286    for (i=0; (size_t)i<kvs_name_list.num_kvs_names;++i){
1287        TEST_CHK(!strcmp(kvs_name_list.kvs_names[i], kvs_names[i]));
1288    }
1289    fdb_free_kvs_name_list(&kvs_name_list);
1290
1291    s = fdb_kvs_close(kv1);
1292    TEST_CHK(s == FDB_RESULT_SUCCESS);
1293    s = fdb_kvs_close(kv2);
1294    TEST_CHK(s == FDB_RESULT_SUCCESS);
1295    s = fdb_close(dbfile);
1296    TEST_CHK(s == FDB_RESULT_SUCCESS);
1297
1298    s = fdb_shutdown();
1299    TEST_CHK(s == FDB_RESULT_SUCCESS);
1300
1301    memleak_end();
1302
1303    if (opt & MULTI_KV_VAR_CMP) {
1304        TEST_RESULT("multiple KV instances transaction test "
1305                    "(custom key order)");
1306    } else {
1307        TEST_RESULT("multiple KV instances transaction test");
1308    }
1309}
1310
1311void multi_kv_snapshot_test(uint8_t opt, size_t chunksize)
1312{
1313    TEST_INIT();
1314
1315    int n = 100;
1316    int i, r;
1317    char key[256], value[256];
1318    char keystr[] = "key%06d";
1319    char valuestr[] = "value%08d(%s)";
1320    fdb_file_handle *dbfile;
1321    fdb_kvs_handle *db, *kv1, *kv2;
1322    fdb_kvs_handle *snap1, *snap2;
1323    fdb_seqnum_t seq1, seq2;
1324    fdb_config config;
1325    fdb_kvs_config kvs_config;
1326    fdb_doc *doc;
1327    fdb_status s;
1328
1329    sprintf(value, SHELL_DEL" multi_kv_test*");
1330    r = system(value);
1331    (void)r;
1332
1333    memleak_start();
1334
1335    config = fdb_get_default_config();
1336    kvs_config = fdb_get_default_kvs_config();
1337    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
1338    config.chunksize = chunksize;
1339    config.multi_kv_instances = true;
1340    config.wal_threshold = 1000;
1341    config.buffercache_size = 0;
1342
1343    s = fdb_open(&dbfile, "./multi_kv_test", &config);
1344    TEST_CHK(s == FDB_RESULT_SUCCESS);
1345    if (opt & MULTI_KV_VAR_CMP) {
1346        kvs_config.custom_cmp = _multi_kv_test_keycmp;
1347    }
1348    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1349    TEST_CHK(s == FDB_RESULT_SUCCESS);
1350    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1351    TEST_CHK(s == FDB_RESULT_SUCCESS);
1352    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1353    TEST_CHK(s == FDB_RESULT_SUCCESS);
1354
1355    // write documents first time
1356    for (i=0;i<n;++i){
1357        sprintf(key, keystr, i);
1358        sprintf(value, valuestr, i, "default(commit1)");
1359        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1360        s = fdb_set(db, doc);
1361        TEST_CHK(s == FDB_RESULT_SUCCESS);
1362        fdb_doc_free(doc);
1363        sprintf(value, valuestr, i, "kv1(commit1)");
1364        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1365        s = fdb_set(kv1, doc);
1366        TEST_CHK(s == FDB_RESULT_SUCCESS);
1367        fdb_doc_free(doc);
1368        sprintf(value, valuestr, i, "kv2(commit1)");
1369        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1370        s = fdb_set(kv2, doc);
1371        TEST_CHK(s == FDB_RESULT_SUCCESS);
1372        fdb_doc_free(doc);
1373    }
1374    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1375    TEST_CHK(s == FDB_RESULT_SUCCESS);
1376    s = fdb_get_kvs_seqnum(kv1, &seq1);
1377    TEST_CHK(s == FDB_RESULT_SUCCESS);
1378
1379    // write documents second time
1380    for (i=0;i<n;++i){
1381        sprintf(key, keystr, i);
1382        sprintf(value, valuestr, i, "default(commit2)");
1383        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1384        s = fdb_set(db, doc);
1385        TEST_CHK(s == FDB_RESULT_SUCCESS);
1386        fdb_doc_free(doc);
1387        sprintf(value, valuestr, i, "kv1(commit2)");
1388        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1389        s = fdb_set(kv1, doc);
1390        TEST_CHK(s == FDB_RESULT_SUCCESS);
1391        fdb_doc_free(doc);
1392        sprintf(value, valuestr, i, "kv2(commit2)");
1393        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1394        s = fdb_set(kv2, doc);
1395        TEST_CHK(s == FDB_RESULT_SUCCESS);
1396        fdb_doc_free(doc);
1397    }
1398    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1399    TEST_CHK(s == FDB_RESULT_SUCCESS);
1400    s = fdb_get_kvs_seqnum(kv2, &seq2);
1401    TEST_CHK(s == FDB_RESULT_SUCCESS);
1402
1403    // write documents third time
1404    for (i=0;i<n;++i){
1405        sprintf(key, keystr, i);
1406        sprintf(value, valuestr, i, "default(commit3)");
1407        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1408        s = fdb_set(db, doc);
1409        TEST_CHK(s == FDB_RESULT_SUCCESS);
1410        fdb_doc_free(doc);
1411        sprintf(value, valuestr, i, "kv1(commit3)");
1412        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1413        s = fdb_set(kv1, doc);
1414        TEST_CHK(s == FDB_RESULT_SUCCESS);
1415        fdb_doc_free(doc);
1416        sprintf(value, valuestr, i, "kv2(commit3)");
1417        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1418        s = fdb_set(kv2, doc);
1419        TEST_CHK(s == FDB_RESULT_SUCCESS);
1420        fdb_doc_free(doc);
1421    }
1422    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1423    TEST_CHK(s == FDB_RESULT_SUCCESS);
1424
1425    // create snapshots
1426    s = fdb_snapshot_open(kv1, &snap1, seq1);
1427    TEST_CHK(s == FDB_RESULT_SUCCESS);
1428    s = fdb_snapshot_open(kv2, &snap2, seq2);
1429    TEST_CHK(s == FDB_RESULT_SUCCESS);
1430
1431    // retrieve
1432    for (i=0;i<n;++i){
1433        sprintf(key, keystr, i);
1434        sprintf(value, valuestr, i, "kv1(commit3)");
1435        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1436        s = fdb_get(kv1, doc);
1437        TEST_CHK(s == FDB_RESULT_SUCCESS);
1438        TEST_CMP(value, doc->body, doc->bodylen);
1439        fdb_doc_free(doc);
1440
1441        sprintf(value, valuestr, i, "kv2(commit3)");
1442        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1443        s = fdb_get(kv2, doc);
1444        TEST_CHK(s == FDB_RESULT_SUCCESS);
1445        TEST_CMP(value, doc->body, doc->bodylen);
1446        fdb_doc_free(doc);
1447
1448        sprintf(value, valuestr, i, "kv1(commit1)");
1449        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1450        s = fdb_get(snap1, doc);
1451        TEST_CHK(s == FDB_RESULT_SUCCESS);
1452        TEST_CMP(value, doc->body, doc->bodylen);
1453        fdb_doc_free(doc);
1454
1455        sprintf(value, valuestr, i, "kv2(commit2)");
1456        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1457        s = fdb_get(snap2, doc);
1458        TEST_CHK(s == FDB_RESULT_SUCCESS);
1459        TEST_CMP(value, doc->body, doc->bodylen);
1460        fdb_doc_free(doc);
1461    }
1462
1463    s = fdb_kvs_close(snap1);
1464    TEST_CHK(s == FDB_RESULT_SUCCESS);
1465    s = fdb_kvs_close(snap2);
1466    TEST_CHK(s == FDB_RESULT_SUCCESS);
1467
1468    s = fdb_kvs_close(kv1);
1469    TEST_CHK(s == FDB_RESULT_SUCCESS);
1470    s = fdb_kvs_close(kv2);
1471    TEST_CHK(s == FDB_RESULT_SUCCESS);
1472    s = fdb_close(dbfile);
1473    TEST_CHK(s == FDB_RESULT_SUCCESS);
1474
1475    s = fdb_shutdown();
1476    TEST_CHK(s == FDB_RESULT_SUCCESS);
1477
1478    memleak_end();
1479
1480    if (opt & MULTI_KV_VAR_CMP) {
1481        TEST_RESULT("multiple KV instances snapshot test "
1482                    "(custom key order)");
1483    } else {
1484        TEST_RESULT("multiple KV instances snapshot test");
1485    }
1486}
1487
1488void multi_kv_rollback_test(uint8_t opt, size_t chunksize)
1489{
1490    TEST_INIT();
1491
1492    int n = 100;
1493    int i, r;
1494    char key[256], value[256];
1495    char keystr[] = "key%06d";
1496    char valuestr[] = "value%08d(%s)";
1497    fdb_file_handle *dbfile;
1498    fdb_kvs_handle *db, *kv1, *kv2;
1499    fdb_seqnum_t seq1, seq2, seq3;
1500    fdb_config config;
1501    fdb_kvs_config kvs_config;
1502    fdb_doc *doc;
1503    fdb_status s;
1504
1505    char *kvs_names[] = {NULL, (char*)"kv1", (char*)"kv2"};
1506    fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp,
1507                                           _multi_kv_test_keycmp,
1508                                           _multi_kv_test_keycmp};
1509
1510    sprintf(value, SHELL_DEL" multi_kv_test*");
1511    r = system(value);
1512    (void)r;
1513
1514    memleak_start();
1515
1516    config = fdb_get_default_config();
1517    kvs_config = fdb_get_default_kvs_config();
1518    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
1519    config.chunksize = chunksize;
1520    config.multi_kv_instances = true;
1521    config.wal_threshold = 1000;
1522    config.buffercache_size = 0;
1523    // for rollback, disable block reusing
1524    config.block_reusing_threshold = 0;
1525
1526    if (opt & MULTI_KV_VAR_CMP) {
1527        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1528                                3, kvs_names, functions);
1529        TEST_CHK(s == FDB_RESULT_SUCCESS);
1530    } else {
1531        s = fdb_open(&dbfile, "./multi_kv_test", &config);
1532        TEST_CHK(s == FDB_RESULT_SUCCESS);
1533    }
1534    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1535    TEST_CHK(s == FDB_RESULT_SUCCESS);
1536    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1537    TEST_CHK(s == FDB_RESULT_SUCCESS);
1538    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1539    TEST_CHK(s == FDB_RESULT_SUCCESS);
1540
1541    // write documents first time
1542    for (i=0;i<n;++i){
1543        sprintf(key, keystr, i);
1544        sprintf(value, valuestr, i, "default(commit1)");
1545        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1546        s = fdb_set(db, doc);
1547        TEST_CHK(s == FDB_RESULT_SUCCESS);
1548        fdb_doc_free(doc);
1549        sprintf(value, valuestr, i, "kv1(commit1)");
1550        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1551        s = fdb_set(kv1, doc);
1552        TEST_CHK(s == FDB_RESULT_SUCCESS);
1553        if (i%15 == 0) s = fdb_set(kv1, doc);
1554        TEST_CHK(s == FDB_RESULT_SUCCESS);
1555        fdb_doc_free(doc);
1556        sprintf(value, valuestr, i, "kv2(commit1)");
1557        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1558        s = fdb_set(kv2, doc);
1559        TEST_CHK(s == FDB_RESULT_SUCCESS);
1560        if (i%27 == 0) s = fdb_set(kv2, doc);
1561        TEST_CHK(s == FDB_RESULT_SUCCESS);
1562        fdb_doc_free(doc);
1563    }
1564    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1565    TEST_CHK(s == FDB_RESULT_SUCCESS);
1566    s = fdb_get_kvs_seqnum(kv1, &seq1);
1567    TEST_CHK(s == FDB_RESULT_SUCCESS);
1568
1569    // write documents second time
1570    for (i=0;i<n;++i){
1571        sprintf(key, keystr, i);
1572        sprintf(value, valuestr, i, "default(commit2)");
1573        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1574        s = fdb_set(db, doc);
1575        TEST_CHK(s == FDB_RESULT_SUCCESS);
1576        fdb_doc_free(doc);
1577        sprintf(value, valuestr, i, "kv1(commit2)");
1578        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1579        s = fdb_set(kv1, doc);
1580        TEST_CHK(s == FDB_RESULT_SUCCESS);
1581        if (i%15 == 0) s = fdb_set(kv1, doc);
1582        TEST_CHK(s == FDB_RESULT_SUCCESS);
1583        fdb_doc_free(doc);
1584        sprintf(value, valuestr, i, "kv2(commit2)");
1585        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1586        s = fdb_set(kv2, doc);
1587        TEST_CHK(s == FDB_RESULT_SUCCESS);
1588        if (i%27 == 0) s = fdb_set(kv2, doc);
1589        TEST_CHK(s == FDB_RESULT_SUCCESS);
1590        fdb_doc_free(doc);
1591    }
1592    s = fdb_commit(dbfile, FDB_COMMIT_MANUAL_WAL_FLUSH);
1593    TEST_CHK(s == FDB_RESULT_SUCCESS);
1594    s = fdb_get_kvs_seqnum(db, &seq2);
1595    TEST_CHK(s == FDB_RESULT_SUCCESS);
1596
1597    // write documents third time
1598    for (i=0;i<n;++i){
1599        sprintf(key, keystr, i);
1600        sprintf(value, valuestr, i, "default(commit3)");
1601        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1602        s = fdb_set(db, doc);
1603        TEST_CHK(s == FDB_RESULT_SUCCESS);
1604        fdb_doc_free(doc);
1605        sprintf(value, valuestr, i, "kv1(commit3)");
1606        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1607        s = fdb_set(kv1, doc);
1608        TEST_CHK(s == FDB_RESULT_SUCCESS);
1609        if (i%15 == 0) s = fdb_set(kv1, doc);
1610        TEST_CHK(s == FDB_RESULT_SUCCESS);
1611        fdb_doc_free(doc);
1612        sprintf(value, valuestr, i, "kv2(commit3)");
1613        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1614        s = fdb_set(kv2, doc);
1615        TEST_CHK(s == FDB_RESULT_SUCCESS);
1616        if (i%27 == 0) s = fdb_set(kv2, doc);
1617        TEST_CHK(s == FDB_RESULT_SUCCESS);
1618        fdb_doc_free(doc);
1619    }
1620    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1621    TEST_CHK(s == FDB_RESULT_SUCCESS);
1622    s = fdb_get_kvs_seqnum(kv2, &seq3);
1623    TEST_CHK(s == FDB_RESULT_SUCCESS);
1624
1625    // write documents third time
1626    for (i=0;i<n;++i){
1627        sprintf(key, keystr, i);
1628        sprintf(value, valuestr, i, "default(commit4)");
1629        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1630        s = fdb_set(db, doc);
1631        TEST_CHK(s == FDB_RESULT_SUCCESS);
1632        fdb_doc_free(doc);
1633        sprintf(value, valuestr, i, "kv1(commit4)");
1634        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1635        s = fdb_set(kv1, doc);
1636        TEST_CHK(s == FDB_RESULT_SUCCESS);
1637        if (i%15 == 0) s = fdb_set(kv1, doc);
1638        TEST_CHK(s == FDB_RESULT_SUCCESS);
1639        fdb_doc_free(doc);
1640        sprintf(value, valuestr, i, "kv2(commit4)");
1641        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1642        s = fdb_set(kv2, doc);
1643        TEST_CHK(s == FDB_RESULT_SUCCESS);
1644        if (i%27 == 0) s = fdb_set(kv2, doc);
1645        TEST_CHK(s == FDB_RESULT_SUCCESS);
1646        fdb_doc_free(doc);
1647    }
1648    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1649    TEST_CHK(s == FDB_RESULT_SUCCESS);
1650
1651    // rollback kv1 using seq1
1652    s = fdb_rollback(&kv1, seq1);
1653    TEST_CHK(s == FDB_RESULT_SUCCESS);
1654
1655    // retrieve check
1656    for (i=0;i<n;++i){
1657        sprintf(key, keystr, i);
1658        sprintf(value, valuestr, i, "default(commit4)");
1659        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1660        s = fdb_get(db, doc);
1661        TEST_CHK(s == FDB_RESULT_SUCCESS);
1662        TEST_CMP(value, doc->body, doc->bodylen);
1663        fdb_doc_free(doc);
1664        sprintf(value, valuestr, i, "kv1(commit1)");
1665        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1666        s = fdb_get(kv1, doc);
1667        TEST_CHK(s == FDB_RESULT_SUCCESS);
1668        TEST_CMP(value, doc->body, doc->bodylen);
1669        fdb_doc_free(doc);
1670        sprintf(value, valuestr, i, "kv2(commit4)");
1671        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1672        s = fdb_get(kv2, doc);
1673        TEST_CHK(s == FDB_RESULT_SUCCESS);
1674        TEST_CMP(value, doc->body, doc->bodylen);
1675        fdb_doc_free(doc);
1676    }
1677
1678    // rollback db using seq2
1679    s = fdb_rollback(&db, seq2);
1680    TEST_CHK(s == FDB_RESULT_SUCCESS);
1681
1682    // retrieve check
1683    for (i=0;i<n;++i){
1684        sprintf(key, keystr, i);
1685        sprintf(value, valuestr, i, "default(commit2)");
1686        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1687        s = fdb_get(db, doc);
1688        TEST_CHK(s == FDB_RESULT_SUCCESS);
1689        TEST_CMP(value, doc->body, doc->bodylen);
1690        fdb_doc_free(doc);
1691        sprintf(value, valuestr, i, "kv1(commit1)");
1692        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1693        s = fdb_get(kv1, doc);
1694        TEST_CHK(s == FDB_RESULT_SUCCESS);
1695        TEST_CMP(value, doc->body, doc->bodylen);
1696        fdb_doc_free(doc);
1697        sprintf(value, valuestr, i, "kv2(commit4)");
1698        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1699        s = fdb_get(kv2, doc);
1700        TEST_CHK(s == FDB_RESULT_SUCCESS);
1701        TEST_CMP(value, doc->body, doc->bodylen);
1702        fdb_doc_free(doc);
1703    }
1704
1705    // rollback db using seq3
1706    s = fdb_rollback(&kv2, seq3);
1707    TEST_CHK(s == FDB_RESULT_SUCCESS);
1708
1709    // retrieve check
1710    for (i=0;i<n;++i){
1711        sprintf(key, keystr, i);
1712        sprintf(value, valuestr, i, "default(commit2)");
1713        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1714        s = fdb_get(db, doc);
1715        TEST_CHK(s == FDB_RESULT_SUCCESS);
1716        TEST_CMP(value, doc->body, doc->bodylen);
1717        fdb_doc_free(doc);
1718        sprintf(value, valuestr, i, "kv1(commit1)");
1719        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1720        s = fdb_get(kv1, doc);
1721        TEST_CHK(s == FDB_RESULT_SUCCESS);
1722        TEST_CMP(value, doc->body, doc->bodylen);
1723        fdb_doc_free(doc);
1724        sprintf(value, valuestr, i, "kv2(commit3)");
1725        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1726        s = fdb_get(kv2, doc);
1727        TEST_CHK(s == FDB_RESULT_SUCCESS);
1728        TEST_CMP(value, doc->body, doc->bodylen);
1729        fdb_doc_free(doc);
1730    }
1731
1732    // close & re-open
1733    s = fdb_kvs_close(kv1);
1734    TEST_CHK(s == FDB_RESULT_SUCCESS);
1735    s = fdb_kvs_close(kv2);
1736    TEST_CHK(s == FDB_RESULT_SUCCESS);
1737    s = fdb_close(dbfile);
1738    TEST_CHK(s == FDB_RESULT_SUCCESS);
1739
1740    if (opt & MULTI_KV_VAR_CMP) {
1741        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1742                                3, kvs_names, functions);
1743        TEST_CHK(s == FDB_RESULT_SUCCESS);
1744    } else {
1745        s = fdb_open(&dbfile, "./multi_kv_test", &config);
1746        TEST_CHK(s == FDB_RESULT_SUCCESS);
1747    }
1748    TEST_CHK(s == FDB_RESULT_SUCCESS);
1749    fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1750    fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1751    fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1752
1753    // retrieve check after re-open
1754    for (i=0;i<n;++i){
1755        sprintf(key, keystr, i);
1756        sprintf(value, valuestr, i, "default(commit2)");
1757        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1758        s = fdb_get(db, doc);
1759        TEST_CHK(s == FDB_RESULT_SUCCESS);
1760        TEST_CMP(value, doc->body, doc->bodylen);
1761        fdb_doc_free(doc);
1762        sprintf(value, valuestr, i, "kv1(commit1)");
1763        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1764        s = fdb_get(kv1, doc);
1765        TEST_CHK(s == FDB_RESULT_SUCCESS);
1766        TEST_CMP(value, doc->body, doc->bodylen);
1767        fdb_doc_free(doc);
1768        sprintf(value, valuestr, i, "kv2(commit3)");
1769        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1770        s = fdb_get(kv2, doc);
1771        TEST_CHK(s == FDB_RESULT_SUCCESS);
1772        TEST_CMP(value, doc->body, doc->bodylen);
1773        fdb_doc_free(doc);
1774    }
1775
1776    fdb_kvs_close(kv1);
1777    fdb_kvs_close(kv2);
1778    fdb_close(dbfile);
1779
1780    fdb_shutdown();
1781
1782    memleak_end();
1783
1784    if (opt & MULTI_KV_VAR_CMP) {
1785        TEST_RESULT("multiple KV instances rollback test "
1786                    "(custom key order)");
1787    } else {
1788        TEST_RESULT("multiple KV instances rollback test");
1789    }
1790}
1791
1792void multi_kv_custom_cmp_test()
1793{
1794    TEST_INIT();
1795
1796    int n = 1000;
1797    int i, r;
1798    char key[256], value[256];
1799    char keyBuf[256], valueBuf[256];
1800    char keystr[] = "key%06d";
1801    char valuestr[] = "value%08d(%s)";
1802    fdb_file_handle *dbfile;
1803    fdb_kvs_handle *db, *kv1, *kv2;
1804    fdb_config config;
1805    fdb_kvs_config kvs_config;
1806    fdb_doc *doc;
1807    fdb_iterator *it;
1808    fdb_status s;
1809
1810    sprintf(value, SHELL_DEL" multi_kv_test*");
1811    r = system(value);
1812    (void)r;
1813
1814    memleak_start();
1815
1816    config = fdb_get_default_config();
1817    kvs_config = fdb_get_default_kvs_config();
1818    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
1819    config.multi_kv_instances = true;
1820    config.wal_threshold = 256;
1821    config.wal_flush_before_commit = false;
1822    config.buffercache_size = 0;
1823
1824    s = fdb_open(&dbfile, "./multi_kv_test", &config);
1825    TEST_CHK(s == FDB_RESULT_SUCCESS);
1826    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1827    TEST_CHK(s == FDB_RESULT_SUCCESS);
1828
1829    // insert using 'default' instance
1830    for (i=0;i<n;++i) {
1831        sprintf(key, keystr, i);
1832        sprintf(value, valuestr, i, "default");
1833        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1834        s = fdb_set(db, doc);
1835        TEST_CHK(s == FDB_RESULT_SUCCESS);
1836        fdb_doc_free(doc);
1837    }
1838    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1839    TEST_CHK(s == FDB_RESULT_SUCCESS);
1840
1841    // create 'kv1' using custom cmp function
1842    kvs_config.custom_cmp = _multi_kv_test_keycmp;
1843    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1844    TEST_CHK(s == FDB_RESULT_SUCCESS);
1845
1846    // insert using 'kv1' instance
1847    for (i=0;i<n;++i) {
1848        sprintf(key, keystr, i);
1849        sprintf(value, valuestr, i, "kv1_custom_cmp");
1850        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1851        s = fdb_set(kv1, doc);
1852        TEST_CHK(s == FDB_RESULT_SUCCESS);
1853        fdb_doc_free(doc);
1854    }
1855    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1856    TEST_CHK(s == FDB_RESULT_SUCCESS);
1857
1858    // retrieve check
1859    for (i=0;i<n;++i) {
1860        sprintf(key, keystr, i);
1861        sprintf(value, valuestr, i, "default");
1862        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1863        s = fdb_get(db, doc);
1864        TEST_CHK(s == FDB_RESULT_SUCCESS);
1865        TEST_CMP(value, doc->body, doc->bodylen);
1866        fdb_doc_free(doc);
1867
1868        sprintf(value, valuestr, i, "kv1_custom_cmp");
1869        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1870        s = fdb_get(kv1, doc);
1871        TEST_CHK(s == FDB_RESULT_SUCCESS);
1872        TEST_CMP(value, doc->body, doc->bodylen);
1873        fdb_doc_free(doc);
1874    }
1875
1876    // close & reopen handles
1877    s = fdb_close(dbfile);
1878    TEST_CHK(s == FDB_RESULT_SUCCESS);
1879    kvs_config.custom_cmp = NULL;
1880    s = fdb_open(&dbfile, "./multi_kv_test", &config);
1881    TEST_CHK(s != FDB_RESULT_SUCCESS); // must fail
1882
1883    { // retry with wrong cmp function
1884        char *kvs_names[] = {NULL};
1885        fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp};
1886        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1887                                1, kvs_names, functions);
1888        TEST_CHK(s != FDB_RESULT_SUCCESS); // must fail
1889    }
1890
1891    { // retry with correct function
1892        char *kvs_names[] = {(char*)"kv1"};
1893        fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp};
1894        s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
1895                                1, kvs_names, functions);
1896        TEST_CHK(s == FDB_RESULT_SUCCESS); // must succeed this time
1897    }
1898
1899    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
1900    TEST_CHK(s == FDB_RESULT_SUCCESS);
1901    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
1902    TEST_CHK(s == FDB_RESULT_SUCCESS);
1903
1904    // retrieve check
1905    for (i=0;i<n;++i) {
1906        sprintf(key, keystr, i);
1907        sprintf(value, valuestr, i, "default");
1908        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1909        s = fdb_get(db, doc);
1910        TEST_CHK(s == FDB_RESULT_SUCCESS);
1911        TEST_CMP(value, doc->body, doc->bodylen);
1912        fdb_doc_free(doc);
1913
1914        sprintf(value, valuestr, i, "kv1_custom_cmp");
1915        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1916        s = fdb_get(kv1, doc);
1917        TEST_CHK(s == FDB_RESULT_SUCCESS);
1918        TEST_CMP(value, doc->body, doc->bodylen);
1919        fdb_doc_free(doc);
1920    }
1921
1922    // create one more KV store
1923    kvs_config.custom_cmp = NULL;
1924    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
1925    TEST_CHK(s == FDB_RESULT_SUCCESS);
1926
1927    // insert using 'kv2' instance
1928    for (i=0;i<n;++i) {
1929        sprintf(key, keystr, i);
1930        sprintf(value, valuestr, i, "kv2");
1931        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1932        s = fdb_set(kv2, doc);
1933        TEST_CHK(s == FDB_RESULT_SUCCESS);
1934        fdb_doc_free(doc);
1935    }
1936    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1937    TEST_CHK(s == FDB_RESULT_SUCCESS);
1938
1939    // retrieve check
1940    for (i=0;i<n;++i) {
1941        sprintf(key, keystr, i);
1942        sprintf(value, valuestr, i, "default");
1943        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1944        s = fdb_get(db, doc);
1945        TEST_CHK(s == FDB_RESULT_SUCCESS);
1946        TEST_CMP(value, doc->body, doc->bodylen);
1947        fdb_doc_free(doc);
1948
1949        sprintf(value, valuestr, i, "kv1_custom_cmp");
1950        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1951        s = fdb_get(kv1, doc);
1952        TEST_CHK(s == FDB_RESULT_SUCCESS);
1953        TEST_CMP(value, doc->body, doc->bodylen);
1954        fdb_doc_free(doc);
1955
1956        sprintf(value, valuestr, i, "kv2");
1957        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1958        s = fdb_get(kv2, doc);
1959        TEST_CHK(s == FDB_RESULT_SUCCESS);
1960        TEST_CMP(value, doc->body, doc->bodylen);
1961        fdb_doc_free(doc);
1962    }
1963
1964    // update all documents
1965    for (i=0;i<n;++i) {
1966        sprintf(key, keystr, i);
1967        sprintf(value, valuestr, i, "default(updated)");
1968        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1969        s = fdb_set(db, doc);
1970        TEST_CHK(s == FDB_RESULT_SUCCESS);
1971        fdb_doc_free(doc);
1972
1973        sprintf(key, keystr, i);
1974        sprintf(value, valuestr, i, "kv1_custom_cmp(updated)");
1975        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1976        s = fdb_set(kv1, doc);
1977        TEST_CHK(s == FDB_RESULT_SUCCESS);
1978        fdb_doc_free(doc);
1979
1980        sprintf(key, keystr, i);
1981        sprintf(value, valuestr, i, "kv2(updated)");
1982        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
1983        s = fdb_set(kv2, doc);
1984        TEST_CHK(s == FDB_RESULT_SUCCESS);
1985        fdb_doc_free(doc);
1986    }
1987    // WAL flush at once
1988    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
1989    TEST_CHK(s == FDB_RESULT_SUCCESS);
1990
1991    // retrieve check
1992    for (i=0;i<n;++i) {
1993        sprintf(key, keystr, i);
1994        sprintf(value, valuestr, i, "default(updated)");
1995        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
1996        s = fdb_get(db, doc);
1997        TEST_CHK(s == FDB_RESULT_SUCCESS);
1998        TEST_CMP(value, doc->body, doc->bodylen);
1999        fdb_doc_free(doc);
2000
2001        sprintf(value, valuestr, i, "kv1_custom_cmp(updated)");
2002        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2003        s = fdb_get(kv1, doc);
2004        TEST_CHK(s == FDB_RESULT_SUCCESS);
2005        TEST_CMP(value, doc->body, doc->bodylen);
2006        fdb_doc_free(doc);
2007
2008        sprintf(value, valuestr, i, "kv2(updated)");
2009        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2010        s = fdb_get(kv2, doc);
2011        TEST_CHK(s == FDB_RESULT_SUCCESS);
2012        TEST_CMP(value, doc->body, doc->bodylen);
2013        fdb_doc_free(doc);
2014    }
2015
2016    // do compaction
2017    s = fdb_compact(dbfile, "./multi_kv_test2");
2018    TEST_CHK(s == FDB_RESULT_SUCCESS);
2019
2020    // retrieve check
2021    for (i=0;i<n;++i) {
2022        sprintf(key, keystr, i);
2023        sprintf(value, valuestr, i, "default(updated)");
2024        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2025        s = fdb_get(db, doc);
2026        TEST_CHK(s == FDB_RESULT_SUCCESS);
2027        TEST_CMP(value, doc->body, doc->bodylen);
2028        fdb_doc_free(doc);
2029
2030        sprintf(value, valuestr, i, "kv1_custom_cmp(updated)");
2031        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2032        s = fdb_get(kv1, doc);
2033        TEST_CHK(s == FDB_RESULT_SUCCESS);
2034        TEST_CMP(value, doc->body, doc->bodylen);
2035        fdb_doc_free(doc);
2036
2037        sprintf(value, valuestr, i, "kv2(updated)");
2038        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2039        s = fdb_get(kv2, doc);
2040        TEST_CHK(s == FDB_RESULT_SUCCESS);
2041        TEST_CMP(value, doc->body, doc->bodylen);
2042        fdb_doc_free(doc);
2043    }
2044
2045    // pre-allocate memory and re-use it for the iterator return document
2046    s = fdb_doc_create(&doc, NULL, 0, NULL, 0, NULL, 0);
2047    TEST_CHK(s == FDB_RESULT_SUCCESS);
2048    doc->key = &keyBuf[0];
2049    doc->body = &valueBuf[0];
2050
2051    // create full iterator for 'kv1'
2052    i = 0;
2053    s = fdb_iterator_init(kv1, &it, NULL, 0, NULL, 0, FDB_ITR_NONE);
2054    TEST_CHK(s == FDB_RESULT_SUCCESS);
2055    do {
2056        s = fdb_iterator_get(it, &doc);
2057        TEST_CHK(s == FDB_RESULT_SUCCESS);
2058        sprintf(key, keystr, i);
2059        sprintf(value, valuestr, i, "kv1_custom_cmp(updated)");
2060        TEST_CMP(doc->key, key, doc->keylen);
2061        TEST_CMP(doc->body, value, doc->bodylen);
2062        i++;
2063    } while (fdb_iterator_next(it) == FDB_RESULT_SUCCESS);
2064    TEST_CHK(i == n);
2065    s = fdb_iterator_close(it);
2066    TEST_CHK(s == FDB_RESULT_SUCCESS);
2067
2068    s = fdb_close(dbfile);
2069    TEST_CHK(s == FDB_RESULT_SUCCESS);
2070    s = fdb_shutdown();
2071    TEST_CHK(s == FDB_RESULT_SUCCESS);
2072    // release the pre-allocated memory for the iterator return document
2073    doc->key = NULL;
2074    doc->body = NULL;
2075    s = fdb_doc_free(doc);
2076    TEST_CHK(s == FDB_RESULT_SUCCESS);
2077    memleak_end();
2078
2079    TEST_RESULT("multiple KV instances custom comparison function test");
2080}
2081
2082void multi_kv_fdb_open_custom_cmp_test()
2083{
2084    // Unit test for MB-12593
2085    TEST_INIT();
2086
2087    int n = 1000;
2088    int i, r;
2089    char key[256], value[256];
2090    char keystr[] = "key%06d";
2091    char valuestr[] = "value%08d(%s)";
2092    fdb_file_handle *dbfile;
2093    fdb_kvs_handle *db, *kv1, *kv2;
2094    fdb_config config;
2095    fdb_kvs_config kvs_config;
2096    fdb_doc *doc;
2097    fdb_status s;
2098
2099    char *kvs_names[] = {(char*)"default", (char*)"kv1", (char*)"kv2"};
2100    fdb_custom_cmp_variable functions[] = {_multi_kv_test_keycmp,
2101                                           _multi_kv_test_keycmp,
2102                                           NULL};
2103
2104    sprintf(value, SHELL_DEL" multi_kv_test*");
2105    r = system(value);
2106    (void)r;
2107
2108    memleak_start();
2109
2110    config = fdb_get_default_config();
2111    kvs_config = fdb_get_default_kvs_config();
2112    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
2113    config.multi_kv_instances = true;
2114    config.wal_threshold = 256;
2115    config.wal_flush_before_commit = false;
2116    config.buffercache_size = 0;
2117
2118    s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
2119                            3, kvs_names, functions);
2120    TEST_CHK(s == FDB_RESULT_SUCCESS);
2121    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2122    TEST_CHK(s == FDB_RESULT_SUCCESS);
2123    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
2124    TEST_CHK(s == FDB_RESULT_SUCCESS);
2125
2126    kvs_config.custom_cmp = _multi_kv_test_keycmp;
2127    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
2128    TEST_CHK(s == FDB_RESULT_SUCCESS);
2129
2130    // insert using 'default' instance
2131    for (i=0;i<n;++i) {
2132        sprintf(key, keystr, i);
2133        sprintf(value, valuestr, i, "default");
2134        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
2135        s = fdb_set(db, doc);
2136        TEST_CHK(s == FDB_RESULT_SUCCESS);
2137        fdb_doc_free(doc);
2138    }
2139
2140    // insert using 'kv1' instance
2141    for (i=0;i<n;++i) {
2142        sprintf(key, keystr, i);
2143        sprintf(value, valuestr, i, "kv1_custom_cmp");
2144        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
2145        s = fdb_set(kv1, doc);
2146        TEST_CHK(s == FDB_RESULT_SUCCESS);
2147        fdb_doc_free(doc);
2148    }
2149
2150    // insert using 'kv2' instance
2151    for (i=0;i<n;++i) {
2152        sprintf(key, keystr, i);
2153        sprintf(value, valuestr, i, "kv2");
2154        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
2155        s = fdb_set(kv2, doc);
2156        TEST_CHK(s == FDB_RESULT_SUCCESS);
2157        fdb_doc_free(doc);
2158    }
2159    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2160    TEST_CHK(s == FDB_RESULT_SUCCESS);
2161    s = fdb_close(dbfile);
2162    TEST_CHK(s == FDB_RESULT_SUCCESS);
2163
2164    s = fdb_open(&dbfile, "./multi_kv_test", &config);
2165    TEST_CHK(s != FDB_RESULT_SUCCESS); // must fail
2166
2167    s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
2168                            3, kvs_names, functions);
2169    TEST_CHK(s != FDB_RESULT_SUCCESS); // must fail
2170
2171    functions[2] = _multi_kv_test_keycmp;
2172    s = fdb_open_custom_cmp(&dbfile, "./multi_kv_test", &config,
2173                            3, kvs_names, functions);
2174    TEST_CHK(s == FDB_RESULT_SUCCESS); // must succeed
2175    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2176    TEST_CHK(s == FDB_RESULT_SUCCESS);
2177    s = fdb_kvs_open(dbfile, &kv1, "kv1", &kvs_config);
2178    TEST_CHK(s == FDB_RESULT_SUCCESS);
2179    s = fdb_kvs_open(dbfile, &kv2, "kv2", &kvs_config);
2180    TEST_CHK(s == FDB_RESULT_SUCCESS);
2181
2182    // retrieve check
2183    for (i=0;i<n;++i) {
2184        sprintf(key, keystr, i);
2185        sprintf(value, valuestr, i, "default");
2186        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2187        s = fdb_get(db, doc);
2188        TEST_CHK(s == FDB_RESULT_SUCCESS);
2189        TEST_CMP(value, doc->body, doc->bodylen);
2190        fdb_doc_free(doc);
2191
2192        sprintf(value, valuestr, i, "kv1_custom_cmp");
2193        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2194        s = fdb_get(kv1, doc);
2195        TEST_CHK(s == FDB_RESULT_SUCCESS);
2196        TEST_CMP(value, doc->body, doc->bodylen);
2197        fdb_doc_free(doc);
2198
2199        sprintf(value, valuestr, i, "kv2");
2200        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2201        s = fdb_get(kv2, doc);
2202        TEST_CHK(s == FDB_RESULT_SUCCESS);
2203        TEST_CMP(value, doc->body, doc->bodylen);
2204        fdb_doc_free(doc);
2205    }
2206
2207    s = fdb_close(dbfile);
2208    TEST_CHK(s == FDB_RESULT_SUCCESS);
2209    s = fdb_shutdown();
2210    TEST_CHK(s == FDB_RESULT_SUCCESS);
2211    memleak_end();
2212
2213    TEST_RESULT("multiple KV instances fdb_open_custom_cmp test");
2214}
2215
2216void multi_kv_use_existing_mode_test()
2217{
2218    TEST_INIT();
2219
2220    int n = 1000;
2221    int i, r;
2222    char key[256], value[256];
2223    char keystr[] = "key%06d";
2224    char valuestr[] = "value%08d(%s)";
2225    fdb_file_handle *dbfile;
2226    fdb_kvs_handle *db;
2227    fdb_config config;
2228    fdb_kvs_config kvs_config;
2229    fdb_doc *doc;
2230    fdb_status s;
2231
2232    sprintf(value, SHELL_DEL" multi_kv_test*");
2233    r = system(value);
2234    (void)r;
2235
2236    memleak_start();
2237
2238    config = fdb_get_default_config();
2239    kvs_config = fdb_get_default_kvs_config();
2240    config.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
2241    config.wal_threshold = 256;
2242    config.buffercache_size = 0;
2243
2244    // create DB file under multi KV instance mode
2245    config.multi_kv_instances = true;
2246    s = fdb_open(&dbfile, "./multi_kv_test_multi", &config);
2247    TEST_CHK(s == FDB_RESULT_SUCCESS);
2248    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2249    TEST_CHK(s == FDB_RESULT_SUCCESS);
2250
2251    // insert using 'default' instance
2252    for (i=0;i<n;++i) {
2253        sprintf(key, keystr, i);
2254        sprintf(value, valuestr, i, "default");
2255        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
2256        s = fdb_set(db, doc);
2257        TEST_CHK(s == FDB_RESULT_SUCCESS);
2258        fdb_doc_free(doc);
2259    }
2260
2261    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2262    TEST_CHK(s == FDB_RESULT_SUCCESS);
2263    s = fdb_close(dbfile);
2264    TEST_CHK(s == FDB_RESULT_SUCCESS);
2265
2266    // open under single KV instance mode
2267    config.multi_kv_instances = false;
2268    s = fdb_open(&dbfile, "./multi_kv_test_multi", &config);
2269    TEST_CHK(s == FDB_RESULT_SUCCESS); // must succeed
2270    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2271    TEST_CHK(s == FDB_RESULT_SUCCESS);
2272
2273    // retrieve check
2274    for (i=0;i<n;++i) {
2275        sprintf(key, keystr, i);
2276        sprintf(value, valuestr, i, "default");
2277        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2278        s = fdb_get(db, doc);
2279        TEST_CHK(s == FDB_RESULT_SUCCESS);
2280        TEST_CMP(value, doc->body, doc->bodylen);
2281        fdb_doc_free(doc);
2282    }
2283
2284    s = fdb_close(dbfile);
2285    TEST_CHK(s == FDB_RESULT_SUCCESS);
2286
2287    // create DB file under single KV instance mode
2288    config.multi_kv_instances = false;
2289    s = fdb_open(&dbfile, "./multi_kv_test_single", &config);
2290    TEST_CHK(s == FDB_RESULT_SUCCESS);
2291    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2292    TEST_CHK(s == FDB_RESULT_SUCCESS);
2293
2294    // insert using 'default' instance
2295    for (i=0;i<n;++i) {
2296        sprintf(key, keystr, i);
2297        sprintf(value, valuestr, i, "default");
2298        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, value, strlen(value)+1);
2299        s = fdb_set(db, doc);
2300        TEST_CHK(s == FDB_RESULT_SUCCESS);
2301        fdb_doc_free(doc);
2302    }
2303
2304    s = fdb_commit(dbfile, FDB_COMMIT_NORMAL);
2305    TEST_CHK(s == FDB_RESULT_SUCCESS);
2306    s = fdb_close(dbfile);
2307    TEST_CHK(s == FDB_RESULT_SUCCESS);
2308
2309    // open under multi KV instance mode
2310    config.multi_kv_instances = true;
2311    s = fdb_open(&dbfile, "./multi_kv_test_single", &config);
2312    TEST_CHK(s == FDB_RESULT_SUCCESS); // must succeed
2313    s = fdb_kvs_open(dbfile, &db, NULL, &kvs_config);
2314    TEST_CHK(s == FDB_RESULT_SUCCESS);
2315
2316    // retrieve check
2317    for (i=0;i<n;++i) {
2318        sprintf(key, keystr, i);
2319        sprintf(value, valuestr, i, "default");
2320        fdb_doc_create(&doc, key, strlen(key)+1, NULL, 0, NULL, 0);
2321        s = fdb_get(db, doc);
2322        TEST_CHK(s == FDB_RESULT_SUCCESS);
2323        TEST_CMP(value, doc->body, doc->bodylen);
2324        fdb_doc_free(doc);
2325    }
2326
2327    s = fdb_close(dbfile);
2328    TEST_CHK(s == FDB_RESULT_SUCCESS);
2329
2330    s = fdb_shutdown();
2331    TEST_CHK(s == FDB_RESULT_SUCCESS);
2332    memleak_end();
2333
2334    TEST_RESULT("multiple KV instances use existing mode test");
2335}
2336
2337void *_opening_thread(void *args) {
2338    int nhandles = 100;
2339    fdb_file_handle **dbfile = alca(fdb_file_handle *, nhandles);
2340    fdb_config fconfig = fdb_get_default_config();
2341    fdb_status s;
2342    TEST_INIT();
2343
2344    for (int i = 0; i < nhandles; ++i) {
2345        s = fdb_open(&dbfile[i], "multi_kv_test2", &fconfig);
2346        TEST_CHK(s == FDB_RESULT_SUCCESS);
2347    }
2348    for (int i = 0; i < nhandles; ++i) {
2349        s = fdb_close(dbfile[i]);
2350        TEST_CHK(s == FDB_RESULT_SUCCESS);
2351    }
2352    thread_exit(0);
2353    return NULL;
2354}
2355
2356void multi_kv_open_test()
2357{
2358    TEST_INIT();
2359    memleak_start();
2360
2361    int n = 256;
2362    int nthreads = 7;
2363    thread_t *tid = alca(thread_t, nthreads);
2364    fdb_file_handle *dbfile;
2365    fdb_status status;
2366    fdb_config fconfig;
2367    fdb_kvs_config kvs_config;
2368
2369    // remove previous multi_kv_test files
2370    int r = system(SHELL_DEL" multi_kv_test* > errorlog.txt");
2371    (void)r;
2372
2373    fconfig = fdb_get_default_config();
2374    kvs_config = fdb_get_default_kvs_config();
2375
2376    // open db
2377    status = fdb_open(&dbfile, "multi_kv_test2", &fconfig);
2378    TEST_CHK(status == FDB_RESULT_SUCCESS);
2379
2380    for (int i = 0; i < nthreads; ++i) {
2381        thread_create(&tid[i], _opening_thread, NULL);
2382    }
2383    for (int i = 0; i < n; ++i) {
2384        fdb_kvs_handle *db;
2385        char kvname[8];
2386        sprintf(kvname, "kv_%d", i);
2387        status = fdb_kvs_open(dbfile, &db, kvname, &kvs_config);
2388        TEST_CHK(status == FDB_RESULT_SUCCESS);
2389    }
2390
2391    for (int i = 0; i < nthreads; ++i) {
2392        void *thread_ret;
2393        thread_join(tid[i], &thread_ret);
2394    }
2395
2396    status = fdb_close(dbfile);
2397    TEST_CHK(status == FDB_RESULT_SUCCESS);
2398    status = fdb_shutdown();
2399    TEST_CHK(status == FDB_RESULT_SUCCESS);
2400
2401    memleak_end();
2402    TEST_RESULT("multi KV creation with parallel open");
2403}
2404void multi_kv_close_test()
2405{
2406    TEST_INIT();
2407    memleak_start();
2408
2409    int i, r;
2410    int n = 10;
2411    fdb_file_handle *dbfile1;
2412    fdb_kvs_handle *db1, *db2, *db3, *db4, *db5;
2413    fdb_doc **doc = alca(fdb_doc*, n);
2414    fdb_doc *rdoc;
2415    fdb_status status;
2416    fdb_config fconfig;
2417    fdb_kvs_config kvs_config;
2418
2419    char keybuf[256], metabuf[256], bodybuf[256];
2420
2421    // remove previous multi_kv_test files
2422    r = system(SHELL_DEL" multi_kv_test* > errorlog.txt");
2423    (void)r;
2424
2425    fconfig = fdb_get_default_config();
2426    fconfig.buffercache_size = 0;
2427    fconfig.seqtree_opt = FDB_SEQTREE_USE; // enable seqtree since get_byseq
2428    fconfig.wal_threshold = 8;
2429    fconfig.flags = FDB_OPEN_FLAG_CREATE;
2430    fconfig.purging_interval = 0;
2431    fconfig.compaction_threshold = 0;
2432    fconfig.wal_flush_before_commit = true;
2433
2434    kvs_config = fdb_get_default_kvs_config();
2435
2436    // open db
2437    fdb_open(&dbfile1, "multi_kv_test1", &fconfig);
2438    fdb_kvs_open(dbfile1, &db1, "db1", &kvs_config);
2439    fdb_kvs_open(dbfile1, &db2, "db2", &kvs_config);
2440    fdb_kvs_open(dbfile1, &db3, "db3", &kvs_config);
2441    fdb_kvs_open(dbfile1, &db4, "db4", &kvs_config);
2442    fdb_kvs_open(dbfile1, &db5, "db5", &kvs_config);
2443
2444    // insert documents
2445    for (i=0;i<n;++i){
2446        sprintf(keybuf, "key%d", i);
2447        sprintf(metabuf, "meta%d", i);
2448        sprintf(bodybuf, "body%d", i);
2449        fdb_doc_create(&doc[i], (void*)keybuf, strlen(keybuf),
2450            (void*)metabuf, strlen(metabuf), (void*)bodybuf, strlen(bodybuf));
2451        fdb_set(db1, doc[i]);
2452        fdb_set(db2, doc[i]);
2453        fdb_set(db3, doc[i]);
2454        fdb_set(db4, doc[i]);
2455        fdb_set(db5, doc[i]);
2456    }
2457    // close db3,4
2458    fdb_kvs_close(db3);
2459    fdb_kvs_close(db4);
2460
2461
2462    // insert documents
2463    for (i=0;i<n;++i){
2464        fdb_set(db1, doc[i]);
2465        fdb_set(db2, doc[i]);
2466        fdb_set(db5, doc[i]);
2467    }
2468
2469    // remove db1
2470    fdb_kvs_close(db1);
2471    status = fdb_kvs_remove(dbfile1,"db1");
2472    TEST_CHK(status == FDB_RESULT_SUCCESS);
2473
2474    // commit
2475    status = fdb_commit(dbfile1, FDB_COMMIT_NORMAL);
2476    TEST_CHK(status == FDB_RESULT_SUCCESS);
2477
2478    // remove db5
2479    fdb_kvs_close(db5);
2480    status = fdb_kvs_remove(dbfile1, "db5");
2481    TEST_CHK(status == FDB_RESULT_SUCCESS);
2482
2483    // attempt to read from remaining open kvs
2484    for (i=0; i<n; i++){
2485        fdb_doc_create(&rdoc, doc[i]->key, doc[i]->keylen, NULL, 0, NULL, 0);
2486        status = fdb_get(db2, rdoc);
2487        TEST_CHK(status == FDB_RESULT_SUCCESS);
2488        fdb_doc_free(rdoc);
2489    }
2490
2491    // close db2
2492    status = fdb_kvs_close(db2);
2493    TEST_CHK(status == FDB_RESULT_SUCCESS);
2494
2495    // free resources
2496    for (i=0; i<n; i++){
2497       status = fdb_doc_free(doc[i]);
2498        TEST_CHK(status == FDB_RESULT_SUCCESS);
2499    }
2500
2501    status = fdb_close(dbfile1);
2502    TEST_CHK(status == FDB_RESULT_SUCCESS);
2503    status = fdb_shutdown();
2504    TEST_CHK(status == FDB_RESULT_SUCCESS);
2505
2506    memleak_end();
2507    TEST_RESULT("multi KV close");
2508}
2509
2510int main(){
2511    int i, j;
2512    uint8_t opt;
2513    size_t chunksize;
2514
2515    multi_kv_open_test();
2516    for (j=0;j<3;++j) {
2517        if (j==0) {
2518            chunksize = 8;
2519        } else if (j==1) {
2520            chunksize = 16;
2521        } else {
2522            chunksize = 32;
2523        }
2524        printf("Chunk size: %d bytes\n", (int)chunksize);
2525        for (i=0;i<2;++i){
2526            opt = (i==0)?(0x0):(MULTI_KV_VAR_CMP);
2527            multi_kv_test(opt, chunksize);
2528            multi_kv_iterator_key_test(opt, chunksize);
2529            multi_kv_iterator_seq_test(opt, chunksize);
2530            multi_kv_txn_test(opt, chunksize);
2531            multi_kv_snapshot_test(opt, chunksize);
2532            multi_kv_rollback_test(opt, chunksize);
2533        }
2534    }
2535    multi_kv_custom_cmp_test();
2536    multi_kv_fdb_open_custom_cmp_test();
2537    multi_kv_use_existing_mode_test();
2538    multi_kv_close_test();
2539
2540    return 0;
2541}
2542