]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/tokyocabinet/tcbtest.c
ebl Add tokyocabinet source to bacula
[bacula/bacula] / bacula / src / lib / tokyocabinet / tcbtest.c
1 /*************************************************************************************************
2  * The test cases of the B+ tree database API
3  *                                                      Copyright (C) 2006-2008 Mikio Hirabayashi
4  * This file is part of Tokyo Cabinet.
5  * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of
6  * the GNU Lesser General Public License as published by the Free Software Foundation; either
7  * version 2.1 of the License or any later version.  Tokyo Cabinet is distributed in the hope
8  * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
10  * License for more details.
11  * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12  * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13  * Boston, MA 02111-1307 USA.
14  *************************************************************************************************/
15
16
17 #include <tcutil.h>
18 #include <tcbdb.h>
19 #include "myconf.h"
20
21 #define RECBUFSIZ      32                // buffer for records
22
23
24 /* global variables */
25 const char *g_progname;                  // program name
26 int g_dbgfd;                             // debugging output
27
28
29 /* function prototypes */
30 int main(int argc, char **argv);
31 static void usage(void);
32 static void iprintf(const char *format, ...);
33 static void eprint(TCBDB *bdb, const char *func);
34 static void mprint(TCBDB *bdb);
35 static int myrand(int range);
36 static int runwrite(int argc, char **argv);
37 static int runread(int argc, char **argv);
38 static int runremove(int argc, char **argv);
39 static int runrcat(int argc, char **argv);
40 static int runqueue(int argc, char **argv);
41 static int runmisc(int argc, char **argv);
42 static int runwicked(int argc, char **argv);
43 static int procwrite(const char *path, int rnum, int lmemb, int nmemb, int bnum,
44                      int apow, int fpow, bool mt, BDBCMP cmp, int opts,
45                      int lcnum, int ncnum, int lsmax, int capnum, int omode);
46 static int procread(const char *path, bool mt, BDBCMP cmp, int lcnum, int ncnum,
47                     int omode, bool wb);
48 static int procremove(const char *path, bool mt, BDBCMP cmp, int lcnum, int ncnum, int omode);
49 static int procrcat(const char *path, int rnum,
50                     int lmemb, int nmemb, int bnum, int apow, int fpow,
51                     bool mt, BDBCMP cmp, int opts, int lcnum, int ncnum, int lsmax, int capnum,
52                     int omode, int pnum, bool rl);
53 static int procqueue(const char *path, int rnum, int lmemb, int nmemb, int bnum,
54                      int apow, int fpow, bool mt, BDBCMP cmp, int opts,
55                      int lcnum, int ncnum, int lsmax, int capnum, int omode);
56 static int procmisc(const char *path, int rnum, bool mt, int opts, int omode);
57 static int procwicked(const char *path, int rnum, bool mt, int opts, int omode);
58
59
60 /* main routine */
61 int main(int argc, char **argv){
62   g_progname = argv[0];
63   g_dbgfd = -1;
64   const char *ebuf = getenv("TCDBGFD");
65   if(ebuf) g_dbgfd = atoi(ebuf);
66   srand((unsigned int)(tctime() * 1000) % UINT_MAX);
67   if(argc < 2) usage();
68   int rv = 0;
69   if(!strcmp(argv[1], "write")){
70     rv = runwrite(argc, argv);
71   } else if(!strcmp(argv[1], "read")){
72     rv = runread(argc, argv);
73   } else if(!strcmp(argv[1], "remove")){
74     rv = runremove(argc, argv);
75   } else if(!strcmp(argv[1], "rcat")){
76     rv = runrcat(argc, argv);
77   } else if(!strcmp(argv[1], "queue")){
78     rv = runqueue(argc, argv);
79   } else if(!strcmp(argv[1], "misc")){
80     rv = runmisc(argc, argv);
81   } else if(!strcmp(argv[1], "wicked")){
82     rv = runwicked(argc, argv);
83   } else {
84     usage();
85   }
86   return rv;
87 }
88
89
90 /* print the usage and exit */
91 static void usage(void){
92   fprintf(stderr, "%s: test cases of the B+ tree database API of Tokyo Cabinet\n", g_progname);
93   fprintf(stderr, "\n");
94   fprintf(stderr, "usage:\n");
95   fprintf(stderr, "  %s write [-mt] [-cd|-ci|-cj] [-tl] [-td|-tb] [-lc num] [-nc num]"
96           " [-ls num] [-ca num] [-nl|-nb] path rnum [lmemb [nmemb [bnum [apow [fpow]]]]]\n",
97           g_progname);
98   fprintf(stderr, "  %s read [-mt] [-cd|-ci|-cj] [-lc num] [-nc num] [-nl|-nb] [-wb]"
99           " path\n", g_progname);
100   fprintf(stderr, "  %s remove [-mt] [-cd|-ci|-cj] [-lc num] [-nc num] [-nl|-nb]"
101           " path\n", g_progname);
102   fprintf(stderr, "  %s rcat [-mt] [-cd|-ci|-cj] [-tl] [-td|-tb] [-lc num] [-nc num]"
103           " [-ls num] [-ca num] [-nl|-nb] [-pn num] [-rl] path rnum"
104           " [lmemb [nmemb [bnum [apow [fpow]]]]]\n", g_progname);
105   fprintf(stderr, "  %s queue [-mt] [-cd|-ci|-cj] [-tl] [-td|-tb] [-lc num] [-nc num]"
106           " [-ls num] [-ca num] [-nl|-nb] path rnum [lmemb [nmemb [bnum [apow [fpow]]]]]\n",
107           g_progname);
108   fprintf(stderr, "  %s misc [-mt] [-tl] [-td|-tb] [-nl|-nb] path rnum\n", g_progname);
109   fprintf(stderr, "  %s wicked [-mt] [-tl] [-td|-tb] [-nl|-nb] path rnum\n", g_progname);
110   fprintf(stderr, "\n");
111   exit(1);
112 }
113
114
115 /* print formatted information string and flush the buffer */
116 static void iprintf(const char *format, ...){
117   va_list ap;
118   va_start(ap, format);
119   vprintf(format, ap);
120   fflush(stdout);
121   va_end(ap);
122 }
123
124
125 /* print error message of hash database */
126 static void eprint(TCBDB *bdb, const char *func){
127   const char *path = tcbdbpath(bdb);
128   int ecode = tcbdbecode(bdb);
129   fprintf(stderr, "%s: %s: %s: error: %d: %s\n",
130           g_progname, path ? path : "-", func, ecode, tcbdberrmsg(ecode));
131 }
132
133
134 /* print members of B+ tree database */
135 static void mprint(TCBDB *bdb){
136   if(bdb->hdb->cnt_writerec < 0) return;
137   iprintf("max leaf member: %d\n", tcbdblmemb(bdb));
138   iprintf("max node member: %d\n", tcbdbnmemb(bdb));
139   iprintf("leaf number: %d\n", tcbdblnum(bdb));
140   iprintf("node number: %d\n", tcbdbnnum(bdb));
141   iprintf("bucket number: %lld\n", (long long)tcbdbbnum(bdb));
142   iprintf("used bucket number: %lld\n", (long long)tcbdbbnumused(bdb));
143   iprintf("cnt_saveleaf: %lld\n", (long long)bdb->cnt_saveleaf);
144   iprintf("cnt_loadleaf: %lld\n", (long long)bdb->cnt_loadleaf);
145   iprintf("cnt_killleaf: %lld\n", (long long)bdb->cnt_killleaf);
146   iprintf("cnt_adjleafc: %lld\n", (long long)bdb->cnt_adjleafc);
147   iprintf("cnt_savenode: %lld\n", (long long)bdb->cnt_savenode);
148   iprintf("cnt_loadnode: %lld\n", (long long)bdb->cnt_loadnode);
149   iprintf("cnt_adjnodec: %lld\n", (long long)bdb->cnt_adjnodec);
150   iprintf("cnt_writerec: %lld\n", (long long)bdb->hdb->cnt_writerec);
151   iprintf("cnt_reuserec: %lld\n", (long long)bdb->hdb->cnt_reuserec);
152   iprintf("cnt_moverec: %lld\n", (long long)bdb->hdb->cnt_moverec);
153   iprintf("cnt_readrec: %lld\n", (long long)bdb->hdb->cnt_readrec);
154   iprintf("cnt_searchfbp: %lld\n", (long long)bdb->hdb->cnt_searchfbp);
155   iprintf("cnt_insertfbp: %lld\n", (long long)bdb->hdb->cnt_insertfbp);
156   iprintf("cnt_splicefbp: %lld\n", (long long)bdb->hdb->cnt_splicefbp);
157   iprintf("cnt_dividefbp: %lld\n", (long long)bdb->hdb->cnt_dividefbp);
158   iprintf("cnt_mergefbp: %lld\n", (long long)bdb->hdb->cnt_mergefbp);
159   iprintf("cnt_reducefbp: %lld\n", (long long)bdb->hdb->cnt_reducefbp);
160   iprintf("cnt_appenddrp: %lld\n", (long long)bdb->hdb->cnt_appenddrp);
161   iprintf("cnt_deferdrp: %lld\n", (long long)bdb->hdb->cnt_deferdrp);
162   iprintf("cnt_flushdrp: %lld\n", (long long)bdb->hdb->cnt_flushdrp);
163   iprintf("cnt_adjrecc: %lld\n", (long long)bdb->hdb->cnt_adjrecc);
164 }
165
166
167 /* get a random number */
168 static int myrand(int range){
169   return (int)((double)range * rand() / (RAND_MAX + 1.0));
170 }
171
172
173 /* parse arguments of write command */
174 static int runwrite(int argc, char **argv){
175   char *path = NULL;
176   char *rstr = NULL;
177   char *lmstr = NULL;
178   char *nmstr = NULL;
179   char *bstr = NULL;
180   char *astr = NULL;
181   char *fstr = NULL;
182   bool mt = false;
183   BDBCMP cmp = NULL;
184   int opts = 0;
185   int lcnum = 0;
186   int ncnum = 0;
187   int lsmax = 0;
188   int capnum = 0;
189   int omode = 0;
190   for(int i = 2; i < argc; i++){
191     if(!path && argv[i][0] == '-'){
192       if(!strcmp(argv[i], "-mt")){
193         mt = true;
194       } else if(!strcmp(argv[i], "-cd")){
195         cmp = tcbdbcmpdecimal;
196       } else if(!strcmp(argv[i], "-ci")){
197         cmp = tcbdbcmpint32;
198       } else if(!strcmp(argv[i], "-cj")){
199         cmp = tcbdbcmpint64;
200       } else if(!strcmp(argv[i], "-tl")){
201         opts |= BDBTLARGE;
202       } else if(!strcmp(argv[i], "-td")){
203         opts |= BDBTDEFLATE;
204       } else if(!strcmp(argv[i], "-tb")){
205         opts |= BDBTTCBS;
206       } else if(!strcmp(argv[i], "-lc")){
207         if(++i >= argc) usage();
208         lcnum = atoi(argv[i]);
209       } else if(!strcmp(argv[i], "-nc")){
210         if(++i >= argc) usage();
211         ncnum = atoi(argv[i]);
212       } else if(!strcmp(argv[i], "-ls")){
213         if(++i >= argc) usage();
214         lsmax = atoi(argv[i]);
215       } else if(!strcmp(argv[i], "-ca")){
216         if(++i >= argc) usage();
217         capnum = atoi(argv[i]);
218       } else if(!strcmp(argv[i], "-nl")){
219         omode |= BDBONOLCK;
220       } else if(!strcmp(argv[i], "-nb")){
221         omode |= BDBOLCKNB;
222       } else {
223         usage();
224       }
225     } else if(!path){
226       path = argv[i];
227     } else if(!rstr){
228       rstr = argv[i];
229     } else if(!lmstr){
230       lmstr = argv[i];
231     } else if(!nmstr){
232       nmstr = argv[i];
233     } else if(!bstr){
234       bstr = argv[i];
235     } else if(!astr){
236       astr = argv[i];
237     } else if(!fstr){
238       fstr = argv[i];
239     } else {
240       usage();
241     }
242   }
243   if(!path || !rstr) usage();
244   int rnum = atoi(rstr);
245   if(rnum < 1) usage();
246   int lmemb = lmstr ? atoi(lmstr) : -1;
247   int nmemb = nmstr ? atoi(nmstr) : -1;
248   int bnum = bstr ? atoi(bstr) : -1;
249   int apow = astr ? atoi(astr) : -1;
250   int fpow = fstr ? atoi(fstr) : -1;
251   int rv = procwrite(path, rnum, lmemb, nmemb, bnum, apow, fpow,
252                      mt, cmp, opts, lcnum, ncnum, lsmax, capnum, omode);
253   return rv;
254 }
255
256
257 /* parse arguments of read command */
258 static int runread(int argc, char **argv){
259   char *path = NULL;
260   bool mt = false;
261   BDBCMP cmp = NULL;
262   int lcnum = 0;
263   int ncnum = 0;
264   int omode = 0;
265   bool wb = false;
266   for(int i = 2; i < argc; i++){
267     if(!path && argv[i][0] == '-'){
268       if(!strcmp(argv[i], "-mt")){
269         mt = true;
270       } else if(!strcmp(argv[i], "-cd")){
271         cmp = tcbdbcmpdecimal;
272       } else if(!strcmp(argv[i], "-ci")){
273         cmp = tcbdbcmpint32;
274       } else if(!strcmp(argv[i], "-cj")){
275         cmp = tcbdbcmpint64;
276       } else if(!strcmp(argv[i], "-lc")){
277         if(++i >= argc) usage();
278         lcnum = atoi(argv[i]);
279       } else if(!strcmp(argv[i], "-nc")){
280         if(++i >= argc) usage();
281         ncnum = atoi(argv[i]);
282       } else if(!strcmp(argv[i], "-nl")){
283         omode |= BDBONOLCK;
284       } else if(!strcmp(argv[i], "-nb")){
285         omode |= BDBOLCKNB;
286       } else if(!strcmp(argv[i], "-wb")){
287         wb = true;
288       } else {
289         usage();
290       }
291     } else if(!path){
292       path = argv[i];
293     } else {
294       usage();
295     }
296   }
297   if(!path) usage();
298   int rv = procread(path, mt, cmp, lcnum, ncnum, omode, wb);
299   return rv;
300 }
301
302
303 /* parse arguments of remove command */
304 static int runremove(int argc, char **argv){
305   char *path = NULL;
306   bool mt = false;
307   BDBCMP cmp = NULL;
308   int lcnum = 0;
309   int ncnum = 0;
310   int omode = 0;
311   for(int i = 2; i < argc; i++){
312     if(!path && argv[i][0] == '-'){
313       if(!strcmp(argv[i], "-mt")){
314         mt = true;
315       } else if(!strcmp(argv[i], "-cd")){
316         cmp = tcbdbcmpdecimal;
317       } else if(!strcmp(argv[i], "-ci")){
318         cmp = tcbdbcmpint32;
319       } else if(!strcmp(argv[i], "-cj")){
320         cmp = tcbdbcmpint64;
321       } else if(!strcmp(argv[i], "-lc")){
322         if(++i >= argc) usage();
323         lcnum = atoi(argv[i]);
324       } else if(!strcmp(argv[i], "-nc")){
325         if(++i >= argc) usage();
326         ncnum = atoi(argv[i]);
327       } else if(!strcmp(argv[i], "-nl")){
328         omode |= BDBONOLCK;
329       } else if(!strcmp(argv[i], "-nb")){
330         omode |= BDBOLCKNB;
331       } else {
332         usage();
333       }
334     } else if(!path){
335       path = argv[i];
336     } else {
337       usage();
338     }
339   }
340   if(!path) usage();
341   int rv = procremove(path, mt, cmp, lcnum, ncnum, omode);
342   return rv;
343 }
344
345
346 /* parse arguments of rcat command */
347 static int runrcat(int argc, char **argv){
348   char *path = NULL;
349   char *rstr = NULL;
350   char *lmstr = NULL;
351   char *nmstr = NULL;
352   char *bstr = NULL;
353   char *astr = NULL;
354   char *fstr = NULL;
355   bool mt = false;
356   BDBCMP cmp = NULL;
357   int opts = 0;
358   int lcnum = 0;
359   int ncnum = 0;
360   int lsmax = 0;
361   int capnum = 0;
362   int omode = 0;
363   int pnum = 0;
364   bool rl = false;
365   for(int i = 2; i < argc; i++){
366     if(!path && argv[i][0] == '-'){
367       if(!strcmp(argv[i], "-mt")){
368         mt = true;
369       } else if(!strcmp(argv[i], "-cd")){
370         cmp = tcbdbcmpdecimal;
371       } else if(!strcmp(argv[i], "-ci")){
372         cmp = tcbdbcmpint32;
373       } else if(!strcmp(argv[i], "-cj")){
374         cmp = tcbdbcmpint64;
375       } else if(!strcmp(argv[i], "-tl")){
376         opts |= BDBTLARGE;
377       } else if(!strcmp(argv[i], "-td")){
378         opts |= BDBTDEFLATE;
379       } else if(!strcmp(argv[i], "-tb")){
380         opts |= BDBTTCBS;
381       } else if(!strcmp(argv[i], "-lc")){
382         if(++i >= argc) usage();
383         lcnum = atoi(argv[i]);
384       } else if(!strcmp(argv[i], "-nc")){
385         if(++i >= argc) usage();
386         ncnum = atoi(argv[i]);
387       } else if(!strcmp(argv[i], "-ls")){
388         if(++i >= argc) usage();
389         lsmax = atoi(argv[i]);
390       } else if(!strcmp(argv[i], "-ca")){
391         if(++i >= argc) usage();
392         capnum = atoi(argv[i]);
393       } else if(!strcmp(argv[i], "-nl")){
394         omode |= BDBONOLCK;
395       } else if(!strcmp(argv[i], "-nb")){
396         omode |= BDBOLCKNB;
397       } else if(!strcmp(argv[i], "-pn")){
398         if(++i >= argc) usage();
399         pnum = atoi(argv[i]);
400       } else if(!strcmp(argv[i], "-rl")){
401         rl = true;
402       } else {
403         usage();
404       }
405     } else if(!path){
406       path = argv[i];
407     } else if(!rstr){
408       rstr = argv[i];
409     } else if(!lmstr){
410       lmstr = argv[i];
411     } else if(!nmstr){
412       nmstr = argv[i];
413     } else if(!bstr){
414       bstr = argv[i];
415     } else if(!astr){
416       astr = argv[i];
417     } else if(!fstr){
418       fstr = argv[i];
419     } else {
420       usage();
421     }
422   }
423   if(!path || !rstr) usage();
424   int rnum = atoi(rstr);
425   if(rnum < 1) usage();
426   int lmemb = lmstr ? atoi(lmstr) : -1;
427   int nmemb = nmstr ? atoi(nmstr) : -1;
428   int bnum = bstr ? atoi(bstr) : -1;
429   int apow = astr ? atoi(astr) : -1;
430   int fpow = fstr ? atoi(fstr) : -1;
431   int rv = procrcat(path, rnum, lmemb, nmemb, bnum, apow, fpow, mt, cmp, opts,
432                     lcnum, ncnum, lsmax, capnum, omode, pnum, rl);
433   return rv;
434 }
435
436
437 /* parse arguments of queue command */
438 static int runqueue(int argc, char **argv){
439   char *path = NULL;
440   char *rstr = NULL;
441   char *lmstr = NULL;
442   char *nmstr = NULL;
443   char *bstr = NULL;
444   char *astr = NULL;
445   char *fstr = NULL;
446   bool mt = false;
447   BDBCMP cmp = NULL;
448   int opts = 0;
449   int lcnum = 0;
450   int ncnum = 0;
451   int lsmax = 0;
452   int capnum = 0;
453   int omode = 0;
454   for(int i = 2; i < argc; i++){
455     if(!path && argv[i][0] == '-'){
456       if(!strcmp(argv[i], "-mt")){
457         mt = true;
458       } else if(!strcmp(argv[i], "-cd")){
459         cmp = tcbdbcmpdecimal;
460       } else if(!strcmp(argv[i], "-ci")){
461         cmp = tcbdbcmpint32;
462       } else if(!strcmp(argv[i], "-cj")){
463         cmp = tcbdbcmpint64;
464       } else if(!strcmp(argv[i], "-tl")){
465         opts |= BDBTLARGE;
466       } else if(!strcmp(argv[i], "-td")){
467         opts |= BDBTDEFLATE;
468       } else if(!strcmp(argv[i], "-tb")){
469         opts |= BDBTTCBS;
470       } else if(!strcmp(argv[i], "-lc")){
471         if(++i >= argc) usage();
472         lcnum = atoi(argv[i]);
473       } else if(!strcmp(argv[i], "-nc")){
474         if(++i >= argc) usage();
475         ncnum = atoi(argv[i]);
476       } else if(!strcmp(argv[i], "-ls")){
477         if(++i >= argc) usage();
478         lsmax = atoi(argv[i]);
479       } else if(!strcmp(argv[i], "-ca")){
480         if(++i >= argc) usage();
481         capnum = atoi(argv[i]);
482       } else if(!strcmp(argv[i], "-nl")){
483         omode |= BDBONOLCK;
484       } else if(!strcmp(argv[i], "-nb")){
485         omode |= BDBOLCKNB;
486       } else {
487         usage();
488       }
489     } else if(!path){
490       path = argv[i];
491     } else if(!rstr){
492       rstr = argv[i];
493     } else if(!lmstr){
494       lmstr = argv[i];
495     } else if(!nmstr){
496       nmstr = argv[i];
497     } else if(!bstr){
498       bstr = argv[i];
499     } else if(!astr){
500       astr = argv[i];
501     } else if(!fstr){
502       fstr = argv[i];
503     } else {
504       usage();
505     }
506   }
507   if(!path || !rstr) usage();
508   int rnum = atoi(rstr);
509   if(rnum < 1) usage();
510   int lmemb = lmstr ? atoi(lmstr) : -1;
511   int nmemb = nmstr ? atoi(nmstr) : -1;
512   int bnum = bstr ? atoi(bstr) : -1;
513   int apow = astr ? atoi(astr) : -1;
514   int fpow = fstr ? atoi(fstr) : -1;
515   int rv = procqueue(path, rnum, lmemb, nmemb, bnum, apow, fpow,
516                      mt, cmp, opts, lcnum, ncnum, lsmax, capnum, omode);
517   return rv;
518 }
519
520
521 /* parse arguments of misc command */
522 static int runmisc(int argc, char **argv){
523   char *path = NULL;
524   char *rstr = NULL;
525   bool mt = false;
526   int opts = 0;
527   int omode = 0;
528   for(int i = 2; i < argc; i++){
529     if(!path && argv[i][0] == '-'){
530       if(!strcmp(argv[i], "-mt")){
531         mt = true;
532       } else if(!strcmp(argv[i], "-tl")){
533         opts |= BDBTLARGE;
534       } else if(!strcmp(argv[i], "-td")){
535         opts |= BDBTDEFLATE;
536       } else if(!strcmp(argv[i], "-tb")){
537         opts |= BDBTTCBS;
538       } else if(!strcmp(argv[i], "-nl")){
539         omode |= BDBONOLCK;
540       } else if(!strcmp(argv[i], "-nb")){
541         omode |= BDBOLCKNB;
542       } else {
543         usage();
544       }
545     } else if(!path){
546       path = argv[i];
547     } else if(!rstr){
548       rstr = argv[i];
549     } else {
550       usage();
551     }
552   }
553   if(!path || !rstr) usage();
554   int rnum = atoi(rstr);
555   if(rnum < 1) usage();
556   int rv = procmisc(path, rnum, mt, opts, omode);
557   return rv;
558 }
559
560
561 /* parse arguments of wicked command */
562 static int runwicked(int argc, char **argv){
563   char *path = NULL;
564   char *rstr = NULL;
565   bool mt = false;
566   int opts = 0;
567   int omode = 0;
568   for(int i = 2; i < argc; i++){
569     if(!path && argv[i][0] == '-'){
570       if(!strcmp(argv[i], "-mt")){
571         mt = true;
572       } else if(!strcmp(argv[i], "-tl")){
573         opts |= BDBTLARGE;
574       } else if(!strcmp(argv[i], "-td")){
575         opts |= BDBTDEFLATE;
576       } else if(!strcmp(argv[i], "-tb")){
577         opts |= BDBTTCBS;
578       } else if(!strcmp(argv[i], "-nl")){
579         omode |= BDBONOLCK;
580       } else if(!strcmp(argv[i], "-nb")){
581         omode |= BDBOLCKNB;
582       } else {
583         usage();
584       }
585     } else if(!path){
586       path = argv[i];
587     } else if(!rstr){
588       rstr = argv[i];
589     } else {
590       usage();
591     }
592   }
593   if(!path || !rstr) usage();
594   int rnum = atoi(rstr);
595   if(rnum < 1) usage();
596   int rv = procwicked(path, rnum, mt, opts, omode);
597   return rv;
598 }
599
600
601 /* perform write command */
602 static int procwrite(const char *path, int rnum, int lmemb, int nmemb, int bnum,
603                      int apow, int fpow, bool mt, BDBCMP cmp, int opts,
604                      int lcnum, int ncnum, int lsmax, int capnum, int omode){
605   iprintf("<Writing Test>\n  path=%s  rnum=%d  lmemb=%d  nmemb=%d  bnum=%d  apow=%d  fpow=%d"
606           "  mt=%d  cmp=%p  opts=%d  lcnum=%d  ncnum=%d  lsmax=%d  capnum=%d  omode=%d\n\n",
607           path, rnum, lmemb, nmemb, bnum, apow, fpow, mt, (void *)(intptr_t)cmp,
608           opts, lcnum, ncnum, lsmax, capnum, omode);
609   bool err = false;
610   double stime = tctime();
611   TCBDB *bdb = tcbdbnew();
612   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
613   if(mt && !tcbdbsetmutex(bdb)){
614     eprint(bdb, "tcbdbsetmutex");
615     err = true;
616   }
617   if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)){
618     eprint(bdb, "tcbdbsetcmpfunc");
619     err = true;
620   }
621   if(!tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts)){
622     eprint(bdb, "tcbdbtune");
623     err = true;
624   }
625   if(!tcbdbsetcache(bdb, lcnum, ncnum)){
626     eprint(bdb, "tcbdbsetcache");
627     err = true;
628   }
629   if(!tcbdbsetlsmax(bdb, lsmax)){
630     eprint(bdb, "tcbdbsetlsmax");
631     err = true;
632   }
633   if(!tcbdbsetcapnum(bdb, capnum)){
634     eprint(bdb, "tcbdbsetcapnum");
635     err = true;
636   }
637   if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC)){
638     eprint(bdb, "tcbdbopen");
639     err = true;
640   }
641   for(int i = 1; i <= rnum; i++){
642     char buf[RECBUFSIZ];
643     int len;
644     if(cmp == tcbdbcmpdecimal){
645       len = sprintf(buf, "%d", i);
646     } else if(cmp == tcbdbcmpint32){
647       int32_t lnum = i;
648       memcpy(buf, &lnum, sizeof(lnum));
649       len = sizeof(lnum);
650     } else if(cmp == tcbdbcmpint64){
651       int64_t llnum = i;
652       memcpy(buf, &llnum, sizeof(llnum));
653       len = sizeof(llnum);
654     } else {
655       len = sprintf(buf, "%08d", i);
656     }
657     if(!tcbdbput(bdb, buf, len, buf, len)){
658       eprint(bdb, "tcbdbput");
659       err = true;
660       break;
661     }
662     if(rnum > 250 && i % (rnum / 250) == 0){
663       putchar('.');
664       fflush(stdout);
665       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
666     }
667   }
668   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
669   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
670   mprint(bdb);
671   if(!tcbdbclose(bdb)){
672     eprint(bdb, "tcbdbclose");
673     err = true;
674   }
675   tcbdbdel(bdb);
676   iprintf("time: %.3f\n", tctime() - stime);
677   iprintf("%s\n\n", err ? "error" : "ok");
678   return err ? 1 : 0;
679 }
680
681
682 /* perform read command */
683 static int procread(const char *path, bool mt, BDBCMP cmp, int lcnum, int ncnum,
684                     int omode, bool wb){
685   iprintf("<Reading Test>\n  path=%s  mt=%d  cmp=%p  lcnum=%d  ncnum=%d  omode=%d  wb=%d\n",
686           path, mt, (void *)(intptr_t)cmp, lcnum, ncnum, omode, wb);
687   bool err = false;
688   double stime = tctime();
689   TCBDB *bdb = tcbdbnew();
690   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
691   if(mt && !tcbdbsetmutex(bdb)){
692     eprint(bdb, "tcbdbsetmutex");
693     err = true;
694   }
695   if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)){
696     eprint(bdb, "tcbdbsetcmpfunc");
697     err = true;
698   }
699   if(!tcbdbsetcache(bdb, lcnum, ncnum)){
700     eprint(bdb, "tcbdbsetcache");
701     err = true;
702   }
703   if(!tcbdbopen(bdb, path, BDBOREADER | omode)){
704     eprint(bdb, "tcbdbopen");
705     err = true;
706   }
707   int rnum = tcbdbrnum(bdb);
708   for(int i = 1; i <= rnum; i++){
709     char kbuf[RECBUFSIZ];
710     int ksiz;
711     if(cmp == tcbdbcmpdecimal){
712       ksiz = sprintf(kbuf, "%d", i);
713     } else if(cmp == tcbdbcmpint32){
714       int32_t lnum = i;
715       memcpy(kbuf, &lnum, sizeof(lnum));
716       ksiz = sizeof(lnum);
717     } else if(cmp == tcbdbcmpint64){
718       int64_t llnum = i;
719       memcpy(kbuf, &llnum, sizeof(llnum));
720       ksiz = sizeof(llnum);
721     } else {
722       ksiz = sprintf(kbuf, "%08d", i);
723     }
724     int vsiz;
725     if(wb){
726       int vsiz;
727       const char *vbuf = tcbdbget3(bdb, kbuf, ksiz, &vsiz);
728       if(!vbuf){
729         eprint(bdb, "tcbdbget3");
730         err = true;
731         break;
732       }
733     } else {
734       char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
735       if(!vbuf){
736         eprint(bdb, "tcbdbget");
737         err = true;
738         break;
739       }
740       free(vbuf);
741     }
742     if(rnum > 250 && i % (rnum / 250) == 0){
743       putchar('.');
744       fflush(stdout);
745       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
746     }
747   }
748   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
749   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
750   mprint(bdb);
751   if(!tcbdbclose(bdb)){
752     eprint(bdb, "tcbdbclose");
753     err = true;
754   }
755   tcbdbdel(bdb);
756   iprintf("time: %.3f\n", tctime() - stime);
757   iprintf("%s\n\n", err ? "error" : "ok");
758   return err ? 1 : 0;
759 }
760
761
762 /* perform remove command */
763 static int procremove(const char *path, bool mt, BDBCMP cmp, int lcnum, int ncnum, int omode){
764   iprintf("<Removing Test>\n  path=%s  mt=%d  cmp=%p  lcnum=%d  ncnum=%d  omode=%d\n",
765           path, mt, (void *)(intptr_t)cmp, lcnum, ncnum, omode);
766   bool err = false;
767   double stime = tctime();
768   TCBDB *bdb = tcbdbnew();
769   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
770   if(mt && !tcbdbsetmutex(bdb)){
771     eprint(bdb, "tcbdbsetmutex");
772     err = true;
773   }
774   if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)){
775     eprint(bdb, "tcbdbsetcmpfunc");
776     err = true;
777   }
778   if(!tcbdbsetcache(bdb, lcnum, ncnum)){
779     eprint(bdb, "tcbdbsetcache");
780     err = true;
781   }
782   if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
783     eprint(bdb, "tcbdbopen");
784     err = true;
785   }
786   int rnum = tcbdbrnum(bdb);
787   for(int i = 1; i <= rnum; i++){
788     char kbuf[RECBUFSIZ];
789     int ksiz;
790     if(cmp == tcbdbcmpdecimal){
791       ksiz = sprintf(kbuf, "%d", i);
792     } else if(cmp == tcbdbcmpint32){
793       int32_t lnum = i;
794       memcpy(kbuf, &lnum, sizeof(lnum));
795       ksiz = sizeof(lnum);
796     } else if(cmp == tcbdbcmpint64){
797       int64_t llnum = i;
798       memcpy(kbuf, &llnum, sizeof(llnum));
799       ksiz = sizeof(llnum);
800     } else {
801       ksiz = sprintf(kbuf, "%08d", i);
802     }
803     if(!tcbdbout(bdb, kbuf, ksiz)){
804       eprint(bdb, "tcbdbout");
805       err = true;
806       break;
807     }
808     if(rnum > 250 && i % (rnum / 250) == 0){
809       putchar('.');
810       fflush(stdout);
811       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
812     }
813   }
814   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
815   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
816   mprint(bdb);
817   if(!tcbdbclose(bdb)){
818     eprint(bdb, "tcbdbclose");
819     err = true;
820   }
821   tcbdbdel(bdb);
822   iprintf("time: %.3f\n", tctime() - stime);
823   iprintf("%s\n\n", err ? "error" : "ok");
824   return err ? 1 : 0;
825 }
826
827
828 /* perform rcat command */
829 static int procrcat(const char *path, int rnum,
830                     int lmemb, int nmemb, int bnum, int apow, int fpow,
831                     bool mt, BDBCMP cmp, int opts, int lcnum, int ncnum, int lsmax, int capnum,
832                     int omode, int pnum, bool rl){
833   iprintf("<Random Concatenating Test>\n"
834           "  path=%s  rnum=%d  lmemb=%d  nmemb=%d  bnum=%d  apow=%d  fpow=%d"
835           "  mt=%d  cmp=%p  opts=%d  lcnum=%d  ncnum=%d  lsmax=%d  capnum=%d"
836           "  omode=%d  pnum=%d  rl=%d\n\n",
837           path, rnum, lmemb, nmemb, bnum, apow, fpow, mt, (void *)(intptr_t)cmp,
838           opts, lcnum, ncnum, lsmax, capnum, omode, pnum, rl);
839   if(pnum < 1) pnum = rnum;
840   bool err = false;
841   double stime = tctime();
842   TCBDB *bdb = tcbdbnew();
843   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
844   if(mt && !tcbdbsetmutex(bdb)){
845     eprint(bdb, "tcbdbsetmutex");
846     err = true;
847   }
848   if(!tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts)){
849     eprint(bdb, "tcbdbtune");
850     err = true;
851   }
852   if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)){
853     eprint(bdb, "tcbdbsetcmpfunc");
854     err = true;
855   }
856   if(!tcbdbsetcache(bdb, lcnum, ncnum)){
857     eprint(bdb, "tcbdbsetcache");
858     err = true;
859   }
860   if(!tcbdbsetlsmax(bdb, lsmax)){
861     eprint(bdb, "tcbdbsetlsmax");
862     err = true;
863   }
864   if(!tcbdbsetcapnum(bdb, capnum)){
865     eprint(bdb, "tcbdbsetcapnum");
866     err = true;
867   }
868   if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC | omode)){
869     eprint(bdb, "tcbdbopen");
870     err = true;
871   }
872   for(int i = 1; i <= rnum; i++){
873     char kbuf[RECBUFSIZ];
874     int ksiz;
875     if(cmp == tcbdbcmpdecimal){
876       ksiz = sprintf(kbuf, "%d", myrand(pnum));
877     } else if(cmp == tcbdbcmpint32){
878       int32_t lnum = myrand(pnum);
879       memcpy(kbuf, &lnum, sizeof(lnum));
880       ksiz = sizeof(lnum);
881     } else if(cmp == tcbdbcmpint64){
882       int64_t llnum = myrand(pnum);
883       memcpy(kbuf, &llnum, sizeof(llnum));
884       ksiz = sizeof(llnum);
885     } else {
886       ksiz = sprintf(kbuf, "%08d", myrand(pnum));
887     }
888     if(rl){
889       char vbuf[PATH_MAX];
890       int vsiz = myrand(PATH_MAX);
891       for(int j = 0; j < vsiz; j++){
892         vbuf[j] = myrand(0x100);
893       }
894       if(!tcbdbputcat(bdb, kbuf, ksiz, vbuf, vsiz)){
895         eprint(bdb, "tcbdbputcat");
896         err = true;
897         break;
898       }
899     } else {
900       if(!tcbdbputcat(bdb, kbuf, ksiz, kbuf, ksiz)){
901         eprint(bdb, "tcbdbputcat");
902         err = true;
903         break;
904       }
905     }
906     if(rnum > 250 && i % (rnum / 250) == 0){
907       putchar('.');
908       fflush(stdout);
909       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
910     }
911   }
912   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
913   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
914   mprint(bdb);
915   if(!tcbdbclose(bdb)){
916     eprint(bdb, "tcbdbclose");
917     err = true;
918   }
919   tcbdbdel(bdb);
920   iprintf("time: %.3f\n", tctime() - stime);
921   iprintf("%s\n\n", err ? "error" : "ok");
922   return err ? 1 : 0;
923 }
924
925
926 /* perform queue command */
927 static int procqueue(const char *path, int rnum, int lmemb, int nmemb, int bnum,
928                      int apow, int fpow, bool mt, BDBCMP cmp, int opts,
929                      int lcnum, int ncnum, int lsmax, int capnum, int omode){
930   iprintf("<Queueing Test>\n  path=%s  rnum=%d  lmemb=%d  nmemb=%d  bnum=%d  apow=%d  fpow=%d"
931           "  mt=%d  cmp=%p  opts=%d  lcnum=%d  ncnum=%d  lsmax=%d  capnum=%d  omode=%d\n\n",
932           path, rnum, lmemb, nmemb, bnum, apow, fpow, mt, (void *)(intptr_t)cmp,
933           opts, lcnum, ncnum, lsmax, capnum, omode);
934   bool err = false;
935   double stime = tctime();
936   TCBDB *bdb = tcbdbnew();
937   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
938   if(mt && !tcbdbsetmutex(bdb)){
939     eprint(bdb, "tcbdbsetmutex");
940     err = true;
941   }
942   if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)){
943     eprint(bdb, "tcbdbsetcmpfunc");
944     err = true;
945   }
946   if(!tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts)){
947     eprint(bdb, "tcbdbtune");
948     err = true;
949   }
950   if(!tcbdbsetcache(bdb, lcnum, ncnum)){
951     eprint(bdb, "tcbdbsetcache");
952     err = true;
953   }
954   if(!tcbdbsetlsmax(bdb, lsmax)){
955     eprint(bdb, "tcbdbsetlsmax");
956     err = true;
957   }
958   if(!tcbdbsetcapnum(bdb, capnum)){
959     eprint(bdb, "tcbdbsetcapnum");
960     err = true;
961   }
962   if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC)){
963     eprint(bdb, "tcbdbopen");
964     err = true;
965   }
966   int deqfreq = (lmemb > 0) ? lmemb * 2 : 256;
967   BDBCUR *cur = tcbdbcurnew(bdb);
968   for(int i = 1; i <= rnum; i++){
969     char buf[RECBUFSIZ];
970     int len;
971     if(cmp == tcbdbcmpdecimal){
972       len = sprintf(buf, "%d", i);
973     } else if(cmp == tcbdbcmpint32){
974       int32_t lnum = i;
975       memcpy(buf, &lnum, sizeof(lnum));
976       len = sizeof(lnum);
977     } else if(cmp == tcbdbcmpint64){
978       int64_t llnum = i;
979       memcpy(buf, &llnum, sizeof(llnum));
980       len = sizeof(llnum);
981     } else {
982       len = sprintf(buf, "%08d", i);
983     }
984     if(!tcbdbput(bdb, buf, len, buf, len)){
985       eprint(bdb, "tcbdbput");
986       err = true;
987       break;
988     }
989     if(myrand(deqfreq) == 0){
990       if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
991         eprint(bdb, "tcbdbcurfirst");
992         err = true;
993         break;
994       }
995       int num = myrand(deqfreq * 2 + 1);
996       while(num >= 0){
997         if(tcbdbcurout(cur)){
998           num--;
999         } else {
1000           if(tcbdbecode(bdb) != TCENOREC){
1001             eprint(bdb, "tcbdbcurout");
1002             err = true;
1003           }
1004           break;
1005         }
1006       }
1007       if(err) break;
1008     }
1009     if(rnum > 250 && i % (rnum / 250) == 0){
1010       putchar('.');
1011       fflush(stdout);
1012       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1013     }
1014   }
1015   if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
1016     eprint(bdb, "tcbdbcurfirst");
1017     err = true;
1018   }
1019   while(true){
1020     if(tcbdbcurout(cur)) continue;
1021     if(tcbdbecode(bdb) != TCENOREC){
1022       eprint(bdb, "tcbdbcurout");
1023       err = true;
1024     }
1025     break;
1026   }
1027   tcbdbcurdel(cur);
1028   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
1029   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
1030   mprint(bdb);
1031   if(!tcbdbclose(bdb)){
1032     eprint(bdb, "tcbdbclose");
1033     err = true;
1034   }
1035   tcbdbdel(bdb);
1036   iprintf("time: %.3f\n", tctime() - stime);
1037   iprintf("%s\n\n", err ? "error" : "ok");
1038   return err ? 1 : 0;
1039 }
1040
1041
1042 /* perform misc command */
1043 static int procmisc(const char *path, int rnum, bool mt, int opts, int omode){
1044   iprintf("<Miscellaneous Test>\n  path=%s  rnum=%d  mt=%d  opts=%d  omode=%d\n\n",
1045           path, rnum, mt, opts, omode);
1046   bool err = false;
1047   double stime = tctime();
1048   TCBDB *bdb = tcbdbnew();
1049   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
1050   if(mt && !tcbdbsetmutex(bdb)){
1051     eprint(bdb, "tcbdbsetmutex");
1052     err = true;
1053   }
1054   if(!tcbdbtune(bdb, 10, 10, rnum / 50, 100, -1, opts)){
1055     eprint(bdb, "tcbdbtune");
1056     err = true;
1057   }
1058   if(!tcbdbsetcache(bdb, 128, 256)){
1059     eprint(bdb, "tcbdbsetcache");
1060     err = true;
1061   }
1062   if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC | omode)){
1063     eprint(bdb, "tcbdbopen");
1064     err = true;
1065   }
1066   iprintf("writing:\n");
1067   for(int i = 1; i <= rnum; i++){
1068     char buf[RECBUFSIZ];
1069     int len = sprintf(buf, "%08d", i);
1070     if(!tcbdbputkeep(bdb, buf, len, buf, len)){
1071       eprint(bdb, "tcbdbputkeep");
1072       err = true;
1073       break;
1074     }
1075     if(rnum > 250 && i % (rnum / 250) == 0){
1076       putchar('.');
1077       fflush(stdout);
1078       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1079     }
1080   }
1081   iprintf("reading:\n");
1082   for(int i = 1; i <= rnum; i++){
1083     char kbuf[RECBUFSIZ];
1084     int ksiz = sprintf(kbuf, "%08d", i);
1085     int vsiz;
1086     char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
1087     if(!vbuf){
1088       eprint(bdb, "tcbdbget");
1089       err = true;
1090       break;
1091     } else if(vsiz != ksiz || memcmp(vbuf, kbuf, vsiz)){
1092       eprint(bdb, "(validation)");
1093       err = true;
1094       free(vbuf);
1095       break;
1096     }
1097     free(vbuf);
1098     if(rnum > 250 && i % (rnum / 250) == 0){
1099       putchar('.');
1100       fflush(stdout);
1101       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1102     }
1103   }
1104   if(tcbdbrnum(bdb) != rnum){
1105     eprint(bdb, "(validation)");
1106     err = true;
1107   }
1108   iprintf("random writing:\n");
1109   for(int i = 1; i <= rnum; i++){
1110     char kbuf[RECBUFSIZ];
1111     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1112     char vbuf[RECBUFSIZ];
1113     int vsiz = myrand(RECBUFSIZ);
1114     memset(vbuf, '*', vsiz);
1115     if(!tcbdbput(bdb, kbuf, ksiz, vbuf, vsiz)){
1116       eprint(bdb, "tcbdbput");
1117       err = true;
1118       break;
1119     }
1120     int rsiz;
1121     char *rbuf = tcbdbget(bdb, kbuf, ksiz, &rsiz);
1122     if(!rbuf){
1123       eprint(bdb, "tcbdbget");
1124       err = true;
1125       break;
1126     }
1127     if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1128       eprint(bdb, "(validation)");
1129       err = true;
1130       free(rbuf);
1131       break;
1132     }
1133     if(rnum > 250 && i % (rnum / 250) == 0){
1134       putchar('.');
1135       fflush(stdout);
1136       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1137     }
1138     free(rbuf);
1139   }
1140   iprintf("word writing:\n");
1141   const char *words[] = {
1142     "a", "A", "bb", "BB", "ccc", "CCC", "dddd", "DDDD", "eeeee", "EEEEEE",
1143     "mikio", "hirabayashi", "tokyo", "cabinet", "hyper", "estraier", "19780211", "birth day",
1144     "one", "first", "two", "second", "three", "third", "four", "fourth", "five", "fifth",
1145     "_[1]_", "uno", "_[2]_", "dos", "_[3]_", "tres", "_[4]_", "cuatro", "_[5]_", "cinco",
1146     "[\xe5\xb9\xb3\xe6\x9e\x97\xe5\xb9\xb9\xe9\x9b\x84]", "[\xe9\xa6\xac\xe9\xb9\xbf]", NULL
1147   };
1148   for(int i = 0; words[i] != NULL; i += 2){
1149     const char *kbuf = words[i];
1150     int ksiz = strlen(kbuf);
1151     const char *vbuf = words[i+1];
1152     int vsiz = strlen(vbuf);
1153     if(!tcbdbputkeep(bdb, kbuf, ksiz, vbuf, vsiz)){
1154       eprint(bdb, "tcbdbputkeep");
1155       err = true;
1156       break;
1157     }
1158     if(rnum > 250) putchar('.');
1159   }
1160   if(rnum > 250) iprintf(" (%08d)\n", sizeof(words) / sizeof(*words));
1161   iprintf("random erasing:\n");
1162   for(int i = 1; i <= rnum; i++){
1163     char kbuf[RECBUFSIZ];
1164     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1165     if(!tcbdbout(bdb, kbuf, ksiz) && tcbdbecode(bdb) != TCENOREC){
1166       eprint(bdb, "tcbdbout");
1167       err = true;
1168       break;
1169     }
1170     if(rnum > 250 && i % (rnum / 250) == 0){
1171       putchar('.');
1172       fflush(stdout);
1173       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1174     }
1175   }
1176   iprintf("writing:\n");
1177   for(int i = 1; i <= rnum; i++){
1178     char kbuf[RECBUFSIZ];
1179     int ksiz = sprintf(kbuf, "[%d]", i);
1180     char vbuf[RECBUFSIZ];
1181     int vsiz = i % RECBUFSIZ;
1182     memset(vbuf, '*', vsiz);
1183     if(!tcbdbputkeep(bdb, kbuf, ksiz, vbuf, vsiz)){
1184       eprint(bdb, "tcbdbputkeep");
1185       err = true;
1186       break;
1187     }
1188     if(vsiz < 1){
1189       char tbuf[PATH_MAX];
1190       for(int j = 0; j < PATH_MAX; j++){
1191         tbuf[j] = myrand(0x100);
1192       }
1193       if(!tcbdbput(bdb, kbuf, ksiz, tbuf, PATH_MAX)){
1194         eprint(bdb, "tcbdbput");
1195         err = true;
1196         break;
1197       }
1198     }
1199     if(rnum > 250 && i % (rnum / 250) == 0){
1200       putchar('.');
1201       fflush(stdout);
1202       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1203     }
1204   }
1205   iprintf("erasing:\n");
1206   for(int i = 1; i <= rnum; i++){
1207     if(i % 2 == 1){
1208       char kbuf[RECBUFSIZ];
1209       int ksiz = sprintf(kbuf, "[%d]", i);
1210       if(!tcbdbout(bdb, kbuf, ksiz)){
1211         eprint(bdb, "tcbdbout");
1212         err = true;
1213         break;
1214       }
1215       if(tcbdbout(bdb, kbuf, ksiz) || tcbdbecode(bdb) != TCENOREC){
1216         eprint(bdb, "tcbdbout");
1217         err = true;
1218         break;
1219       }
1220     }
1221     if(rnum > 250 && i % (rnum / 250) == 0){
1222       putchar('.');
1223       fflush(stdout);
1224       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1225     }
1226   }
1227   iprintf("random writing and reopening:\n");
1228   for(int i = 1; i <= rnum; i++){
1229     if(myrand(10) == 0){
1230       int ksiz, vsiz;
1231       char *kbuf, *vbuf;
1232       ksiz = (myrand(5) == 0) ? myrand(UINT16_MAX) : myrand(RECBUFSIZ);
1233       kbuf = tcmalloc(ksiz + 1);
1234       for(int j = 0; j < ksiz; j++){
1235         kbuf[j] = 128 + myrand(128);
1236       }
1237       vsiz = (myrand(5) == 0) ? myrand(UINT16_MAX) : myrand(RECBUFSIZ);
1238       vbuf = tcmalloc(vsiz + 1);
1239       for(int j = 0; j < vsiz; j++){
1240         vbuf[j] = myrand(256);
1241       }
1242       switch(myrand(5)){
1243       case 0:
1244         if(!tcbdbput(bdb, kbuf, ksiz, vbuf, vsiz)){
1245           eprint(bdb, "tcbdbput");
1246           err = true;
1247         }
1248         break;
1249       case 1:
1250         if(!tcbdbputcat(bdb, kbuf, ksiz, vbuf, vsiz)){
1251           eprint(bdb, "tcbdbputcat");
1252           err = true;
1253         }
1254         break;
1255       case 2:
1256         if(!tcbdbputdup(bdb, kbuf, ksiz, vbuf, vsiz)){
1257           eprint(bdb, "tcbdbputdup");
1258           err = true;
1259         }
1260         break;
1261       case 3:
1262         if(!tcbdbputdupback(bdb, kbuf, ksiz, vbuf, vsiz)){
1263           eprint(bdb, "tcbdbputdupback");
1264           err = true;
1265         }
1266         break;
1267       default:
1268         if(!tcbdbout(bdb, kbuf, ksiz) && tcbdbecode(bdb) != TCENOREC){
1269           eprint(bdb, "tcbdbout");
1270           err = true;
1271         }
1272         break;
1273       }
1274       free(vbuf);
1275       free(kbuf);
1276     } else {
1277       char kbuf[RECBUFSIZ];
1278       int ksiz = myrand(RECBUFSIZ);
1279       memset(kbuf, '@', ksiz);
1280       char vbuf[RECBUFSIZ];
1281       int vsiz = myrand(RECBUFSIZ);
1282       memset(vbuf, '@', vsiz);
1283       if(!tcbdbput(bdb, kbuf, ksiz, vbuf, vsiz)){
1284         eprint(bdb, "tcbdbputcat");
1285         err = true;
1286         break;
1287       }
1288     }
1289     if(rnum > 250 && i % (rnum / 250) == 0){
1290       putchar('.');
1291       fflush(stdout);
1292       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1293     }
1294   }
1295   if(!tcbdbclose(bdb)){
1296     eprint(bdb, "tcbdbclose");
1297     err = true;
1298   }
1299   if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
1300     eprint(bdb, "tcbdbopen");
1301     err = true;
1302   }
1303   iprintf("checking:\n");
1304   for(int i = 1; i <= rnum; i++){
1305     char kbuf[RECBUFSIZ];
1306     int ksiz = sprintf(kbuf, "[%d]", i);
1307     int vsiz;
1308     char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
1309     if(i % 2 == 0){
1310       if(!vbuf){
1311         eprint(bdb, "tcbdbget");
1312         err = true;
1313         break;
1314       }
1315       if(vsiz != i % RECBUFSIZ && vsiz != PATH_MAX){
1316         eprint(bdb, "(validation)");
1317         err = true;
1318         free(vbuf);
1319         break;
1320       }
1321     } else {
1322       if(vbuf || tcbdbecode(bdb) != TCENOREC){
1323         eprint(bdb, "(validation)");
1324         err = true;
1325         free(vbuf);
1326         break;
1327       }
1328     }
1329     free(vbuf);
1330     if(rnum > 250 && i % (rnum / 250) == 0){
1331       putchar('.');
1332       fflush(stdout);
1333       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1334     }
1335   }
1336   iprintf("writing:\n");
1337   for(int i = 1; i <= rnum; i++){
1338     char buf[RECBUFSIZ];
1339     int len = sprintf(buf, "%08d", i);
1340     if(!tcbdbput(bdb, buf, len, buf, len)){
1341       eprint(bdb, "tcbdbput");
1342       err = true;
1343       break;
1344     }
1345     if(i % 10 == 0){
1346       TCLIST *vals = tclistnew();
1347       for(int j = myrand(5) + 1; j >= 0; j--){
1348         tclistpush(vals, buf, len);
1349       }
1350       if(!tcbdbputdup3(bdb, buf, len, vals)){
1351         eprint(bdb, "tcbdbput3");
1352         err = true;
1353         break;
1354       }
1355       tclistdel(vals);
1356     }
1357     if(rnum > 250 && i % (rnum / 250) == 0){
1358       putchar('.');
1359       fflush(stdout);
1360       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1361     }
1362   }
1363   iprintf("reading:\n");
1364   for(int i = 1; i <= rnum; i++){
1365     char kbuf[RECBUFSIZ];
1366     int ksiz = sprintf(kbuf, "%08d", i);
1367     int vsiz;
1368     char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
1369     if(!vbuf){
1370       eprint(bdb, "tcbdbget");
1371       err = true;
1372       break;
1373     } else if(vsiz != ksiz || memcmp(vbuf, kbuf, vsiz)){
1374       eprint(bdb, "(validation)");
1375       err = true;
1376       free(vbuf);
1377       break;
1378     }
1379     free(vbuf);
1380     if(rnum > 250 && i % (rnum / 250) == 0){
1381       putchar('.');
1382       fflush(stdout);
1383       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1384     }
1385   }
1386   iprintf("word checking:\n");
1387   for(int i = 0; words[i] != NULL; i += 2){
1388     const char *kbuf = words[i];
1389     int ksiz = strlen(kbuf);
1390     const char *vbuf = words[i+1];
1391     int vsiz = strlen(vbuf);
1392     int rsiz;
1393     char *rbuf = tcbdbget(bdb, kbuf, ksiz, &rsiz);
1394     if(!rbuf){
1395       eprint(bdb, "tcbdbget");
1396       err = true;
1397       break;
1398     } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1399       eprint(bdb, "(validation)");
1400       err = true;
1401       free(rbuf);
1402       break;
1403     }
1404     free(rbuf);
1405     if(rnum > 250) putchar('.');
1406   }
1407   if(rnum > 250) iprintf(" (%08d)\n", sizeof(words) / sizeof(*words));
1408   iprintf("cursor checking:\n");
1409   BDBCUR *cur = tcbdbcurnew(bdb);
1410   if(!tcbdbcurfirst(cur)){
1411     eprint(bdb, "tcbdbcurfirst");
1412     err = true;
1413   }
1414   char *kbuf;
1415   int ksiz;
1416   int inum = 0;
1417   for(int i = 1; (kbuf = tcbdbcurkey(cur, &ksiz)) != NULL; i++, inum++){
1418     int vsiz;
1419     char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
1420     if(!vbuf){
1421       eprint(bdb, "tcbdbget");
1422       err = true;
1423       free(kbuf);
1424       break;
1425     }
1426     free(vbuf);
1427     free(kbuf);
1428     tcbdbcurnext(cur);
1429     if(rnum > 250 && i % (rnum / 250) == 0){
1430       putchar('.');
1431       fflush(stdout);
1432       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1433     }
1434   }
1435   if(rnum > 250) iprintf(" (%08d)\n", inum);
1436   if(tcbdbecode(bdb) != TCENOREC || inum != tcbdbrnum(bdb)){
1437     eprint(bdb, "(validation)");
1438     err = true;
1439   }
1440   iprintf("cursor updating:\n");
1441   if(!tcbdbcurfirst(cur)){
1442     eprint(bdb, "tcbdbcurfirst");
1443     err = true;
1444   }
1445   inum = 0;
1446   for(int i = 1; !err && (kbuf = tcbdbcurkey(cur, &ksiz)) != NULL; i++, inum++){
1447     switch(myrand(6)){
1448     case 0:
1449       if(!tcbdbputdup(bdb, kbuf, ksiz, "0123456789", 10)){
1450         eprint(bdb, "tcbdbputcat");
1451         err = true;
1452       }
1453       break;
1454     case 1:
1455       if(!tcbdbout(bdb, kbuf, ksiz)){
1456         eprint(bdb, "tcbdbout");
1457         err = true;
1458       }
1459       break;
1460     case 2:
1461       if(!tcbdbcurput(cur, kbuf, ksiz, BDBCPCURRENT)){
1462         eprint(bdb, "tcbdbcurput");
1463         err = true;
1464       }
1465       break;
1466     case 3:
1467       if(!tcbdbcurput(cur, kbuf, ksiz, BDBCPBEFORE)){
1468         eprint(bdb, "tcbdbcurput");
1469         err = true;
1470       }
1471       break;
1472     case 4:
1473       if(!tcbdbcurput(cur, kbuf, ksiz, BDBCPAFTER)){
1474         eprint(bdb, "tcbdbcurput");
1475         err = true;
1476       }
1477       break;
1478     default:
1479       if(!tcbdbcurout(cur) && tcbdbecode(bdb) != TCENOREC){
1480         eprint(bdb, "tcbdbcurout");
1481         err = true;
1482       }
1483       break;
1484     }
1485     free(kbuf);
1486     tcbdbcurnext(cur);
1487     if(rnum > 250 && i % (rnum / 250) == 0){
1488       putchar('.');
1489       fflush(stdout);
1490       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1491     }
1492   }
1493   if(rnum > 250) iprintf(" (%08d)\n", inum);
1494   if(tcbdbecode(bdb) != TCENOREC){
1495     eprint(bdb, "(validation)");
1496     err = true;
1497   }
1498   if(!tcbdbsync(bdb)){
1499     eprint(bdb, "tcbdbsync");
1500     err = true;
1501   }
1502   iprintf("cursor updating from empty:\n");
1503   tcbdbcurfirst(cur);
1504   inum = 0;
1505   for(int i = 1; (kbuf = tcbdbcurkey(cur, &ksiz)) != NULL; i++, inum++){
1506     free(kbuf);
1507     if(!tcbdbcurout(cur) && tcbdbecode(bdb) != TCENOREC){
1508       eprint(bdb, "tcbdbcurout");
1509       err = true;
1510     }
1511     if(rnum > 250 && i % (rnum / 250) == 0){
1512       putchar('.');
1513       fflush(stdout);
1514       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1515     }
1516   }
1517   if(rnum > 250) iprintf(" (%08d)\n", inum);
1518   if(tcbdbrnum(bdb) != 0){
1519     eprint(bdb, "(validation)");
1520     err = true;
1521   }
1522   if(!tcbdbput2(bdb, "one", "first")){
1523     eprint(bdb, "tcbdbput");
1524     err = true;
1525   }
1526   if(!tcbdbcurlast(cur)){
1527     eprint(bdb, "tcbdbcurlast");
1528     err = true;
1529   }
1530   if(!tcbdbcurput2(cur, "second", BDBCPCURRENT) || !tcbdbcurput2(cur, "first", BDBCPBEFORE) ||
1531      !tcbdbcurput2(cur, "zero", BDBCPBEFORE) || !tcbdbcurput2(cur, "top", BDBCPBEFORE)){
1532     eprint(bdb, "tcbdbcurput2");
1533     err = true;
1534   }
1535   if(!tcbdbcurlast(cur)){
1536     eprint(bdb, "tcbdbcurlast");
1537     err = true;
1538   }
1539   if(!tcbdbcurput2(cur, "third", BDBCPAFTER) || !tcbdbcurput2(cur, "fourth", BDBCPAFTER) ||
1540      !tcbdbcurput2(cur, "end", BDBCPCURRENT) ||  !tcbdbcurput2(cur, "bottom", BDBCPAFTER)){
1541     eprint(bdb, "tcbdbcurput2");
1542     err = true;
1543   }
1544   iprintf("checking transaction commit:\n");
1545   if(!tcbdbtranbegin(bdb)){
1546     eprint(bdb, "tcbdbtranbegin");
1547     err = true;
1548   }
1549   for(int i = 1; i <= rnum; i++){
1550     char kbuf[RECBUFSIZ];
1551     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1552     if(!tcbdbputdup(bdb, kbuf, ksiz, kbuf, ksiz)){
1553       eprint(bdb, "tcbdbputdup");
1554       err = true;
1555       break;
1556     }
1557     if(rnum > 250 && i % (rnum / 250) == 0){
1558       putchar('.');
1559       fflush(stdout);
1560       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1561     }
1562   }
1563   if(!tcbdbtrancommit(bdb)){
1564     eprint(bdb, "tcbdbtrancommit");
1565     err = true;
1566   }
1567   iprintf("checking transaction abort:\n");
1568   uint64_t ornum = tcbdbrnum(bdb);
1569   if(!tcbdbtranbegin(bdb)){
1570     eprint(bdb, "tcbdbtranbegin");
1571     err = true;
1572   }
1573   for(int i = 1; i <= rnum; i++){
1574     char kbuf[RECBUFSIZ];
1575     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1576     if(!tcbdbout(bdb, kbuf, ksiz) && tcbdbecode(bdb) != TCENOREC){
1577       eprint(bdb, "tcbdbout");
1578       err = true;
1579       break;
1580     }
1581     if(rnum > 250 && i % (rnum / 250) == 0){
1582       putchar('.');
1583       fflush(stdout);
1584       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1585     }
1586   }
1587   if(!tcbdbtranabort(bdb)){
1588     eprint(bdb, "tcbdbtranabort");
1589     err = true;
1590   }
1591   if(tcbdbrnum(bdb) != ornum){
1592     eprint(bdb, "(validation)");
1593     err = true;
1594   }
1595   if(ornum > 1000){
1596     if(!tcbdbcurfirst(cur)){
1597       eprint(bdb, "tcbdbcurfirst");
1598       err = true;
1599     }
1600     for(int i = 1; i < 500 && !err && (kbuf = tcbdbcurkey(cur, &ksiz)) != NULL; i++){
1601       int vsiz;
1602       if(myrand(20) == 0){
1603         if(!tcbdbget3(bdb, kbuf, ksiz, &vsiz)){
1604           eprint(bdb, "tcbdbget3");
1605           err = true;
1606         }
1607         if(myrand(2) == 0 && !tcbdbout(bdb, kbuf, ksiz)){
1608           eprint(bdb, "tcbdbget3");
1609           err = true;
1610         }
1611         if(myrand(2) == 0 && !tcbdbputdup(bdb, kbuf, ksiz, kbuf, ksiz)){
1612           eprint(bdb, "tcbdbput");
1613           err = true;
1614         }
1615       } else {
1616         if(!tcbdbcurout(cur)){
1617           eprint(bdb, "tcbdbcurout");
1618           err = true;
1619         }
1620       }
1621       free(kbuf);
1622       if(myrand(30) == 0 && !tcbdbcurfirst(cur)){
1623         eprint(bdb, "tcbdbcurfirst");
1624         err = true;
1625       }
1626     }
1627   }
1628   if(!tcbdbvanish(bdb)){
1629     eprint(bdb, "tcbdbvanish");
1630     err = true;
1631   }
1632   if(!tcbdbtranbegin(bdb)){
1633     eprint(bdb, "tcbdbtranbegin");
1634     err = true;
1635   }
1636   if(!tcbdbput2(bdb, "mikio", "hirabayashi")){
1637     eprint(bdb, "tcbdbput2");
1638     err = true;
1639   }
1640   tcbdbcurdel(cur);
1641   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
1642   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
1643   mprint(bdb);
1644   if(!tcbdbclose(bdb)){
1645     eprint(bdb, "tcbdbclose");
1646     err = true;
1647   }
1648   tcbdbdel(bdb);
1649   iprintf("time: %.3f\n", tctime() - stime);
1650   iprintf("%s\n\n", err ? "error" : "ok");
1651   return err ? 1 : 0;
1652 }
1653
1654
1655 /* perform wicked command */
1656 static int procwicked(const char *path, int rnum, bool mt, int opts, int omode){
1657   iprintf("<Wicked Writing Test>\n  path=%s  rnum=%d  mt=%d  opts=%d  omode=%d\n\n",
1658           path, rnum, mt, opts, omode);
1659   bool err = false;
1660   double stime = tctime();
1661   TCBDB *bdb = tcbdbnew();
1662   if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
1663   if(mt && !tcbdbsetmutex(bdb)){
1664     eprint(bdb, "tcbdbsetmutex");
1665     err = true;
1666   }
1667   if(!tcbdbtune(bdb, 10, 10, rnum / 50, 100, -1, opts)){
1668     eprint(bdb, "tcbdbtune");
1669     err = true;
1670   }
1671   if(!tcbdbsetcache(bdb, 128, 256)){
1672     eprint(bdb, "tcbdbsetcache");
1673     err = true;
1674   }
1675   if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC | omode)){
1676     eprint(bdb, "tcbdbopen");
1677     err = true;
1678   }
1679   BDBCUR *cur = tcbdbcurnew(bdb);
1680   if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
1681     eprint(bdb, "tcbdbcurfirst");
1682     err = true;
1683   }
1684   TCMAP *map = tcmapnew2(rnum / 5);
1685   for(int i = 1; i <= rnum && !err; i++){
1686     char kbuf[RECBUFSIZ];
1687     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1688     char vbuf[RECBUFSIZ];
1689     int vsiz = myrand(RECBUFSIZ);
1690     memset(vbuf, '*', vsiz);
1691     vbuf[vsiz] = '\0';
1692     char *rbuf;
1693     switch(myrand(16)){
1694     case 0:
1695       putchar('0');
1696       if(!tcbdbput(bdb, kbuf, ksiz, vbuf, vsiz)){
1697         eprint(bdb, "tcbdbput");
1698         err = true;
1699       }
1700       tcmapput(map, kbuf, ksiz, vbuf, vsiz);
1701       break;
1702     case 1:
1703       putchar('1');
1704       if(!tcbdbput2(bdb, kbuf, vbuf)){
1705         eprint(bdb, "tcbdbput2");
1706         err = true;
1707       }
1708       tcmapput2(map, kbuf, vbuf);
1709       break;
1710     case 2:
1711       putchar('2');
1712       if(!tcbdbputkeep(bdb, kbuf, ksiz, vbuf, vsiz) && tcbdbecode(bdb) != TCEKEEP){
1713         eprint(bdb, "tcbdbputkeep");
1714         err = true;
1715       }
1716       tcmapputkeep(map, kbuf, ksiz, vbuf, vsiz);
1717       break;
1718     case 3:
1719       putchar('3');
1720       if(!tcbdbputkeep2(bdb, kbuf, vbuf) && tcbdbecode(bdb) != TCEKEEP){
1721         eprint(bdb, "tcbdbputkeep2");
1722         err = true;
1723       }
1724       tcmapputkeep2(map, kbuf, vbuf);
1725       break;
1726     case 4:
1727       putchar('4');
1728       if(!tcbdbputcat(bdb, kbuf, ksiz, vbuf, vsiz)){
1729         eprint(bdb, "tcbdbputcat");
1730         err = true;
1731       }
1732       tcmapputcat(map, kbuf, ksiz, vbuf, vsiz);
1733       break;
1734     case 5:
1735       putchar('5');
1736       if(!tcbdbputcat2(bdb, kbuf, vbuf)){
1737         eprint(bdb, "tcbdbputcat2");
1738         err = true;
1739       }
1740       tcmapputcat2(map, kbuf, vbuf);
1741       break;
1742     case 6:
1743       putchar('6');
1744       if(myrand(10) == 0){
1745         if(!tcbdbout(bdb, kbuf, ksiz) && tcbdbecode(bdb) != TCENOREC){
1746           eprint(bdb, "tcbdbout");
1747           err = true;
1748         }
1749         tcmapout(map, kbuf, ksiz);
1750       }
1751       break;
1752     case 7:
1753       putchar('7');
1754       if(myrand(10) == 0){
1755         if(!tcbdbout2(bdb, kbuf) && tcbdbecode(bdb) != TCENOREC){
1756           eprint(bdb, "tcbdbout2");
1757           err = true;
1758         }
1759         tcmapout2(map, kbuf);
1760       }
1761       break;
1762     case 8:
1763       putchar('8');
1764       if(!(rbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz))){
1765         if(tcbdbecode(bdb) != TCENOREC){
1766           eprint(bdb, "tcbdbget");
1767           err = true;
1768         }
1769         rbuf = tcsprintf("[%d]", myrand(i + 1));
1770         vsiz = strlen(rbuf);
1771       }
1772       vsiz += myrand(vsiz);
1773       if(myrand(3) == 0) vsiz += PATH_MAX;
1774       rbuf = tcrealloc(rbuf, vsiz + 1);
1775       for(int j = 0; j < vsiz; j++){
1776         rbuf[j] = myrand(0x100);
1777       }
1778       if(!tcbdbput(bdb, kbuf, ksiz, rbuf, vsiz)){
1779         eprint(bdb, "tcbdbput");
1780         err = true;
1781       }
1782       tcmapput(map, kbuf, ksiz, rbuf, vsiz);
1783       free(rbuf);
1784       break;
1785     case 9:
1786       putchar('9');
1787       if(!(rbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz)) && tcbdbecode(bdb) != TCENOREC){
1788         eprint(bdb, "tcbdbget");
1789         err = true;
1790       }
1791       free(rbuf);
1792       break;
1793     case 10:
1794       putchar('A');
1795       if(!(rbuf = tcbdbget2(bdb, kbuf)) && tcbdbecode(bdb) != TCENOREC){
1796         eprint(bdb, "tcbdbget");
1797         err = true;
1798       }
1799       free(rbuf);
1800       break;
1801     case 11:
1802       putchar('B');
1803       if(myrand(1) == 0) vsiz = 1;
1804       if(!tcbdbget3(bdb, kbuf, ksiz, &vsiz) && tcbdbecode(bdb) != TCENOREC){
1805         eprint(bdb, "tcbdbget");
1806         err = true;
1807       }
1808       break;
1809     case 12:
1810       putchar('C');
1811       if(myrand(rnum / 50) == 0){
1812         if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
1813           eprint(bdb, "tcbdbcurfirst");
1814           err = true;
1815         }
1816       }
1817       TCXSTR *ikey = tcxstrnew();
1818       TCXSTR *ival = tcxstrnew();
1819       for(int j = myrand(rnum) / 1000 + 1; j >= 0; j--){
1820         if(j % 3 == 0){
1821           if(tcbdbcurrec(cur, ikey, ival)){
1822             if(tcbdbvnum(bdb, tcxstrptr(ikey), tcxstrsize(ikey)) != 1){
1823               eprint(bdb, "(validation)");
1824               err = true;
1825             }
1826             if(tcxstrsize(ival) != tcbdbvsiz(bdb, tcxstrptr(ikey), tcxstrsize(ikey))){
1827               eprint(bdb, "(validation)");
1828               err = true;
1829             }
1830           } else {
1831             int ecode = tcbdbecode(bdb);
1832             if(ecode != TCEINVALID && ecode != TCENOREC){
1833               eprint(bdb, "tcbdbcurrec");
1834               err = true;
1835             }
1836           }
1837         } else {
1838           int iksiz;
1839           char *ikbuf = tcbdbcurkey(cur, &iksiz);
1840           if(ikbuf){
1841             free(ikbuf);
1842           } else {
1843             int ecode = tcbdbecode(bdb);
1844             if(ecode != TCEINVALID && ecode != TCENOREC){
1845               eprint(bdb, "tcbdbcurkey");
1846               err = true;
1847             }
1848           }
1849         }
1850         tcbdbcurnext(cur);
1851       }
1852       tcxstrdel(ival);
1853       tcxstrdel(ikey);
1854       break;
1855     default:
1856       putchar('@');
1857       if(myrand(10000) == 0) srand((unsigned int)(tctime() * 1000) % UINT_MAX);
1858       if(myrand(rnum / 32 + 1) == 0){
1859         if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
1860           eprint(bdb, "tcbdbcurfirst");
1861           err = true;
1862         }
1863         int cnt = myrand(30);
1864         for(int j = 0; j < rnum && !err; j++){
1865           ksiz = sprintf(kbuf, "%d", i + j);
1866           if(myrand(4) == 0){
1867             if(tcbdbout3(bdb, kbuf, ksiz)){
1868               cnt--;
1869             } else if(tcbdbecode(bdb) != TCENOREC){
1870               eprint(bdb, "tcbdbout3");
1871               err = true;
1872             }
1873             tcmapout(map, kbuf, ksiz);
1874           } else if(myrand(30) == 0){
1875             int tksiz;
1876             char *tkbuf = tcbdbcurkey(cur, &tksiz);
1877             if(tkbuf){
1878               if(tcbdbcurout(cur)){
1879                 cnt--;
1880               } else {
1881                 eprint(bdb, "tcbdbcurout");
1882                 err = true;
1883               }
1884               tcmapout(map, tkbuf, tksiz);
1885               free(tkbuf);
1886             } else if(tcbdbecode(bdb) != TCENOREC){
1887               eprint(bdb, "tcbdbcurfirst");
1888               err = true;
1889             }
1890           } else {
1891             if(tcbdbout(bdb, kbuf, ksiz)){
1892               cnt--;
1893             } else if(tcbdbecode(bdb) != TCENOREC){
1894               eprint(bdb, "tcbdbout");
1895               err = true;
1896             }
1897             tcmapout(map, kbuf, ksiz);
1898           }
1899           if(cnt < 0) break;
1900         }
1901       }
1902       break;
1903     }
1904     if(i % 50 == 0) iprintf(" (%08d)\n", i);
1905     if(i == rnum / 2){
1906       if(!tcbdbclose(bdb)){
1907         eprint(bdb, "tcbdbclose");
1908         err = true;
1909       }
1910       if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
1911         eprint(bdb, "tcbdbopen");
1912         err = true;
1913       }
1914     } else if(i == rnum / 4){
1915       char *npath = tcsprintf("%s-tmp", path);
1916       if(!tcbdbcopy(bdb, npath)){
1917         eprint(bdb, "tcbdbcopy");
1918         err = true;
1919       }
1920       TCBDB *nbdb = tcbdbnew();
1921       if(!tcbdbopen(nbdb, npath, BDBOREADER | omode)){
1922         eprint(nbdb, "tcbdbopen");
1923         err = true;
1924       }
1925       tcbdbdel(nbdb);
1926       unlink(npath);
1927       free(npath);
1928       if(!tcbdboptimize(bdb, -1, -1, -1, -1, -1, -1)){
1929         eprint(bdb, "tcbdboptimize");
1930         err = true;
1931       }
1932       if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
1933         eprint(bdb, "tcbdbcurfirst");
1934         err = true;
1935       }
1936     } else if(i == rnum / 8){
1937       if(!tcbdbtranbegin(bdb)){
1938         eprint(bdb, "tcbdbtranbegin");
1939         err = true;
1940       }
1941     } else if(i == rnum / 8 + rnum / 16){
1942       if(!tcbdbtrancommit(bdb)){
1943         eprint(bdb, "tcbdbtrancommit");
1944         err = true;
1945       }
1946     }
1947   }
1948   if(rnum % 50 > 0) iprintf(" (%08d)\n", rnum);
1949   if(!tcbdbsync(bdb)){
1950     eprint(bdb, "tcbdbsync");
1951     err = true;
1952   }
1953   if(tcbdbrnum(bdb) != tcmaprnum(map)){
1954     eprint(bdb, "(validation)");
1955     err = true;
1956   }
1957   for(int i = 1; i <= rnum && !err; i++){
1958     char kbuf[RECBUFSIZ];
1959     int ksiz = sprintf(kbuf, "%d", i - 1);
1960     int vsiz;
1961     const char *vbuf = tcmapget(map, kbuf, ksiz, &vsiz);
1962     int rsiz;
1963     char *rbuf = tcbdbget(bdb, kbuf, ksiz, &rsiz);
1964     if(vbuf){
1965       putchar('.');
1966       if(!rbuf){
1967         eprint(bdb, "tcbdbget");
1968         err = true;
1969       } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1970         eprint(bdb, "(validation)");
1971         err = true;
1972       }
1973     } else {
1974       putchar('*');
1975       if(rbuf || tcbdbecode(bdb) != TCENOREC){
1976         eprint(bdb, "(validation)");
1977         err = true;
1978       }
1979     }
1980     free(rbuf);
1981     if(i % 50 == 0) iprintf(" (%08d)\n", i);
1982   }
1983   if(rnum % 50 > 0) iprintf(" (%08d)\n", rnum);
1984   tcmapiterinit(map);
1985   int ksiz;
1986   const char *kbuf;
1987   for(int i = 1; (kbuf = tcmapiternext(map, &ksiz)) != NULL; i++){
1988     putchar('+');
1989     int vsiz;
1990     const char *vbuf = tcmapiterval(kbuf, &vsiz);
1991     int rsiz;
1992     char *rbuf = tcbdbget(bdb, kbuf, ksiz, &rsiz);
1993     if(!rbuf){
1994       eprint(bdb, "tcbdbget");
1995       err = true;
1996     } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1997       eprint(bdb, "(validation)");
1998       err = true;
1999     }
2000     free(rbuf);
2001     if(!tcbdbout(bdb, kbuf, ksiz)){
2002       eprint(bdb, "tcbdbout");
2003       err = true;
2004     }
2005     if(i % 50 == 0) iprintf(" (%08d)\n", i);
2006   }
2007   int mrnum = tcmaprnum(map);
2008   if(mrnum % 50 > 0) iprintf(" (%08d)\n", mrnum);
2009   if(tcbdbrnum(bdb) != 0){
2010     eprint(bdb, "(validation)");
2011     err = true;
2012   }
2013   tcbdbcurdel(cur);
2014   iprintf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
2015   iprintf("size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
2016   mprint(bdb);
2017   tcmapdel(map);
2018   if(!tcbdbclose(bdb)){
2019     eprint(bdb, "tcbdbclose");
2020     err = true;
2021   }
2022   tcbdbdel(bdb);
2023   iprintf("time: %.3f\n", tctime() - stime);
2024   iprintf("%s\n\n", err ? "error" : "ok");
2025   return err ? 1 : 0;
2026 }
2027
2028
2029
2030 // END OF FILE