]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/tokyocabinet/tchtest.c
ebl Add tokyocabinet source to bacula
[bacula/bacula] / bacula / src / lib / tokyocabinet / tchtest.c
1 /*************************************************************************************************
2  * The test cases of the hash 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 <tchdb.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(TCHDB *hdb, const char *func);
34 static void mprint(TCHDB *hdb);
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 runmisc(int argc, char **argv);
41 static int runwicked(int argc, char **argv);
42 static int procwrite(const char *path, int rnum, int bnum, int apow, int fpow,
43                      bool mt, int opts, int rcnum, int omode, bool as);
44 static int procread(const char *path, bool mt, int rcnum, int omode, bool wb);
45 static int procremove(const char *path, bool mt, int rcnum, int omode);
46 static int procrcat(const char *path, int rnum, int bnum, int apow, int fpow,
47                     bool mt, int opts, int rcnum, int omode, int pnum, bool rl);
48 static int procmisc(const char *path, int rnum, bool mt, int opts, int omode);
49 static int procwicked(const char *path, int rnum, bool mt, int opts, int omode);
50
51
52 /* main routine */
53 int main(int argc, char **argv){
54   g_progname = argv[0];
55   g_dbgfd = -1;
56   const char *ebuf = getenv("TCDBGFD");
57   if(ebuf) g_dbgfd = atoi(ebuf);
58   srand((unsigned int)(tctime() * 1000) % UINT_MAX);
59   if(argc < 2) usage();
60   int rv = 0;
61   if(!strcmp(argv[1], "write")){
62     rv = runwrite(argc, argv);
63   } else if(!strcmp(argv[1], "read")){
64     rv = runread(argc, argv);
65   } else if(!strcmp(argv[1], "remove")){
66     rv = runremove(argc, argv);
67   } else if(!strcmp(argv[1], "rcat")){
68     rv = runrcat(argc, argv);
69   } else if(!strcmp(argv[1], "misc")){
70     rv = runmisc(argc, argv);
71   } else if(!strcmp(argv[1], "wicked")){
72     rv = runwicked(argc, argv);
73   } else {
74     usage();
75   }
76   return rv;
77 }
78
79
80 /* print the usage and exit */
81 static void usage(void){
82   fprintf(stderr, "%s: test cases of the hash database API of Tokyo Cabinet\n", g_progname);
83   fprintf(stderr, "\n");
84   fprintf(stderr, "usage:\n");
85   fprintf(stderr, "  %s write [-mt] [-tl] [-td|-tb] [-rc num] [-nl|-nb] [-as] path rnum"
86           " [bnum [apow [fpow]]]\n", g_progname);
87   fprintf(stderr, "  %s read [-mt] [-rc num] [-nl|-nb] [-wb] path\n", g_progname);
88   fprintf(stderr, "  %s remove [-mt] [-rc num] [-nl|-nb] path\n", g_progname);
89   fprintf(stderr, "  %s rcat [-mt] [-rc num] [-tl] [-td|-tb] [-nl|-nb] [-pn num] [-rl]"
90           " path rnum [bnum [apow [fpow]]]\n", g_progname);
91   fprintf(stderr, "  %s misc [-mt] [-tl] [-td|-tb] [-nl|-nb] path rnum\n", g_progname);
92   fprintf(stderr, "  %s wicked [-mt] [-tl] [-td|-tb] [-nl|-nb] path rnum\n", g_progname);
93   fprintf(stderr, "\n");
94   exit(1);
95 }
96
97
98 /* print formatted information string and flush the buffer */
99 static void iprintf(const char *format, ...){
100   va_list ap;
101   va_start(ap, format);
102   vprintf(format, ap);
103   fflush(stdout);
104   va_end(ap);
105 }
106
107
108 /* print error message of hash database */
109 static void eprint(TCHDB *hdb, const char *func){
110   const char *path = tchdbpath(hdb);
111   int ecode = tchdbecode(hdb);
112   fprintf(stderr, "%s: %s: %s: error: %d: %s\n",
113           g_progname, path ? path : "-", func, ecode, tchdberrmsg(ecode));
114 }
115
116
117 /* print members of hash database */
118 static void mprint(TCHDB *hdb){
119   if(hdb->cnt_writerec < 0) return;
120   iprintf("bucket number: %lld\n", (long long)tchdbbnum(hdb));
121   iprintf("used bucket number: %lld\n", (long long)tchdbbnumused(hdb));
122   iprintf("cnt_writerec: %lld\n", (long long)hdb->cnt_writerec);
123   iprintf("cnt_reuserec: %lld\n", (long long)hdb->cnt_reuserec);
124   iprintf("cnt_moverec: %lld\n", (long long)hdb->cnt_moverec);
125   iprintf("cnt_readrec: %lld\n", (long long)hdb->cnt_readrec);
126   iprintf("cnt_searchfbp: %lld\n", (long long)hdb->cnt_searchfbp);
127   iprintf("cnt_insertfbp: %lld\n", (long long)hdb->cnt_insertfbp);
128   iprintf("cnt_splicefbp: %lld\n", (long long)hdb->cnt_splicefbp);
129   iprintf("cnt_dividefbp: %lld\n", (long long)hdb->cnt_dividefbp);
130   iprintf("cnt_mergefbp: %lld\n", (long long)hdb->cnt_mergefbp);
131   iprintf("cnt_reducefbp: %lld\n", (long long)hdb->cnt_reducefbp);
132   iprintf("cnt_appenddrp: %lld\n", (long long)hdb->cnt_appenddrp);
133   iprintf("cnt_deferdrp: %lld\n", (long long)hdb->cnt_deferdrp);
134   iprintf("cnt_flushdrp: %lld\n", (long long)hdb->cnt_flushdrp);
135   iprintf("cnt_adjrecc: %lld\n", (long long)hdb->cnt_adjrecc);
136 }
137
138
139 /* get a random number */
140 static int myrand(int range){
141   return (int)((double)range * rand() / (RAND_MAX + 1.0));
142 }
143
144
145 /* parse arguments of write command */
146 static int runwrite(int argc, char **argv){
147   char *path = NULL;
148   char *rstr = NULL;
149   char *bstr = NULL;
150   char *astr = NULL;
151   char *fstr = NULL;
152   bool mt = false;
153   int opts = 0;
154   int rcnum = 0;
155   int omode = 0;
156   bool as = false;
157   for(int i = 2; i < argc; i++){
158     if(!path && argv[i][0] == '-'){
159       if(!strcmp(argv[i], "-mt")){
160         mt = true;
161       } else if(!strcmp(argv[i], "-tl")){
162         opts |= HDBTLARGE;
163       } else if(!strcmp(argv[i], "-td")){
164         opts |= HDBTDEFLATE;
165       } else if(!strcmp(argv[i], "-tb")){
166         opts |= HDBTTCBS;
167       } else if(!strcmp(argv[i], "-rc")){
168         if(++i >= argc) usage();
169         rcnum = atoi(argv[i]);
170       } else if(!strcmp(argv[i], "-nl")){
171         omode |= HDBONOLCK;
172       } else if(!strcmp(argv[i], "-nb")){
173         omode |= HDBOLCKNB;
174       } else if(!strcmp(argv[i], "-as")){
175         as = true;
176       } else {
177         usage();
178       }
179     } else if(!path){
180       path = argv[i];
181     } else if(!rstr){
182       rstr = argv[i];
183     } else if(!bstr){
184       bstr = argv[i];
185     } else if(!astr){
186       astr = argv[i];
187     } else if(!fstr){
188       fstr = argv[i];
189     } else {
190       usage();
191     }
192   }
193   if(!path || !rstr) usage();
194   int rnum = atoi(rstr);
195   if(rnum < 1) usage();
196   int bnum = bstr ? atoi(bstr) : -1;
197   int apow = astr ? atoi(astr) : -1;
198   int fpow = fstr ? atoi(fstr) : -1;
199   int rv = procwrite(path, rnum, bnum, apow, fpow, mt, opts, rcnum, omode, as);
200   return rv;
201 }
202
203
204 /* parse arguments of read command */
205 static int runread(int argc, char **argv){
206   char *path = NULL;
207   bool mt = false;
208   int rcnum = 0;
209   int omode = 0;
210   bool wb = false;
211   for(int i = 2; i < argc; i++){
212     if(!path && argv[i][0] == '-'){
213       if(!strcmp(argv[i], "-mt")){
214         mt = true;
215       } else if(!strcmp(argv[i], "-rc")){
216         if(++i >= argc) usage();
217         rcnum = atoi(argv[i]);
218       } else if(!strcmp(argv[i], "-nl")){
219         omode |= HDBONOLCK;
220       } else if(!strcmp(argv[i], "-nb")){
221         omode |= HDBOLCKNB;
222       } else if(!strcmp(argv[i], "-wb")){
223         wb = true;
224       } else {
225         usage();
226       }
227     } else if(!path){
228       path = argv[i];
229     } else {
230       usage();
231     }
232   }
233   if(!path) usage();
234   int rv = procread(path, mt, rcnum, omode, wb);
235   return rv;
236 }
237
238
239 /* parse arguments of remove command */
240 static int runremove(int argc, char **argv){
241   char *path = NULL;
242   bool mt = false;
243   int rcnum = 0;
244   int omode = 0;
245   for(int i = 2; i < argc; i++){
246     if(!path && argv[i][0] == '-'){
247       if(!strcmp(argv[i], "-mt")){
248         mt = true;
249       } else if(!strcmp(argv[i], "-rc")){
250         if(++i >= argc) usage();
251         rcnum = atoi(argv[i]);
252       } else if(!strcmp(argv[i], "-nl")){
253         omode |= HDBONOLCK;
254       } else if(!strcmp(argv[i], "-nb")){
255         omode |= HDBOLCKNB;
256       } else {
257         usage();
258       }
259     } else if(!path){
260       path = argv[i];
261     } else {
262       usage();
263     }
264   }
265   if(!path) usage();
266   int rv = procremove(path, mt, rcnum, omode);
267   return rv;
268 }
269
270
271 /* parse arguments of rcat command */
272 static int runrcat(int argc, char **argv){
273   char *path = NULL;
274   char *rstr = NULL;
275   char *bstr = NULL;
276   char *astr = NULL;
277   char *fstr = NULL;
278   bool mt = false;
279   int opts = 0;
280   int rcnum = 0;
281   int omode = 0;
282   int pnum = 0;
283   bool rl = false;
284   for(int i = 2; i < argc; i++){
285     if(!path && argv[i][0] == '-'){
286       if(!strcmp(argv[i], "-mt")){
287         mt = true;
288       } else if(!strcmp(argv[i], "-tl")){
289         opts |= HDBTLARGE;
290       } else if(!strcmp(argv[i], "-td")){
291         opts |= HDBTDEFLATE;
292       } else if(!strcmp(argv[i], "-tb")){
293         opts |= HDBTTCBS;
294       } else if(!strcmp(argv[i], "-rc")){
295         if(++i >= argc) usage();
296         rcnum = atoi(argv[i]);
297       } else if(!strcmp(argv[i], "-nl")){
298         omode |= HDBONOLCK;
299       } else if(!strcmp(argv[i], "-nb")){
300         omode |= HDBOLCKNB;
301       } else if(!strcmp(argv[i], "-pn")){
302         if(++i >= argc) usage();
303         pnum = atoi(argv[i]);
304       } else if(!strcmp(argv[i], "-rl")){
305         rl = true;
306       } else {
307         usage();
308       }
309     } else if(!path){
310       path = argv[i];
311     } else if(!rstr){
312       rstr = argv[i];
313     } else if(!bstr){
314       bstr = argv[i];
315     } else if(!astr){
316       astr = argv[i];
317     } else if(!fstr){
318       fstr = argv[i];
319     } else {
320       usage();
321     }
322   }
323   if(!path || !rstr) usage();
324   int rnum = atoi(rstr);
325   if(rnum < 1) usage();
326   int bnum = bstr ? atoi(bstr) : -1;
327   int apow = astr ? atoi(astr) : -1;
328   int fpow = fstr ? atoi(fstr) : -1;
329   int rv = procrcat(path, rnum, bnum, apow, fpow, mt, opts, rcnum, omode, pnum, rl);
330   return rv;
331 }
332
333
334 /* parse arguments of misc command */
335 static int runmisc(int argc, char **argv){
336   char *path = NULL;
337   char *rstr = NULL;
338   bool mt = false;
339   int opts = 0;
340   int omode = 0;
341   for(int i = 2; i < argc; i++){
342     if(!path && argv[i][0] == '-'){
343       if(!strcmp(argv[i], "-mt")){
344         mt = true;
345       } else if(!strcmp(argv[i], "-tl")){
346         opts |= HDBTLARGE;
347       } else if(!strcmp(argv[i], "-td")){
348         opts |= HDBTDEFLATE;
349       } else if(!strcmp(argv[i], "-tb")){
350         opts |= HDBTTCBS;
351       } else if(!strcmp(argv[i], "-nl")){
352         omode |= HDBONOLCK;
353       } else if(!strcmp(argv[i], "-nb")){
354         omode |= HDBOLCKNB;
355       } else {
356         usage();
357       }
358     } else if(!path){
359       path = argv[i];
360     } else if(!rstr){
361       rstr = argv[i];
362     } else {
363       usage();
364     }
365   }
366   if(!path || !rstr) usage();
367   int rnum = atoi(rstr);
368   if(rnum < 1) usage();
369   int rv = procmisc(path, rnum, mt, opts, omode);
370   return rv;
371 }
372
373
374 /* parse arguments of wicked command */
375 static int runwicked(int argc, char **argv){
376   char *path = NULL;
377   char *rstr = NULL;
378   bool mt = false;
379   int opts = 0;
380   int omode = 0;
381   for(int i = 2; i < argc; i++){
382     if(!path && argv[i][0] == '-'){
383       if(!strcmp(argv[i], "-mt")){
384         mt = true;
385       } else if(!strcmp(argv[i], "-tl")){
386         opts |= HDBTLARGE;
387       } else if(!strcmp(argv[i], "-td")){
388         opts |= HDBTDEFLATE;
389       } else if(!strcmp(argv[i], "-tb")){
390         opts |= HDBTTCBS;
391       } else if(!strcmp(argv[i], "-nl")){
392         omode |= HDBONOLCK;
393       } else if(!strcmp(argv[i], "-nb")){
394         omode |= HDBOLCKNB;
395       } else {
396         usage();
397       }
398     } else if(!path){
399       path = argv[i];
400     } else if(!rstr){
401       rstr = argv[i];
402     } else {
403       usage();
404     }
405   }
406   if(!path || !rstr) usage();
407   int rnum = atoi(rstr);
408   if(rnum < 1) usage();
409   int rv = procwicked(path, rnum, mt, opts, omode);
410   return rv;
411 }
412
413
414 /* perform write command */
415 static int procwrite(const char *path, int rnum, int bnum, int apow, int fpow,
416                      bool mt, int opts, int rcnum, int omode, bool as){
417   iprintf("<Writing Test>\n  path=%s  rnum=%d  bnum=%d  apow=%d  fpow=%d  mt=%d"
418           "  opts=%d  rcnum=%d  omode=%d  as=%d\n\n",
419           path, rnum, bnum, apow, fpow, mt, opts, rcnum, omode, as);
420   bool err = false;
421   double stime = tctime();
422   TCHDB *hdb = tchdbnew();
423   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
424   if(mt && !tchdbsetmutex(hdb)){
425     eprint(hdb, "tchdbsetmutex");
426     err = true;
427   }
428   if(!tchdbtune(hdb, bnum, apow, fpow, opts)){
429     eprint(hdb, "tchdbtune");
430     err = true;
431   }
432   if(!tchdbsetcache(hdb, rcnum)){
433     eprint(hdb, "tchdbsetcache");
434     err = true;
435   }
436   if(!tchdbopen(hdb, path, HDBOWRITER | HDBOCREAT | HDBOTRUNC | omode)){
437     eprint(hdb, "tchdbopen");
438     err = true;
439   }
440   for(int i = 1; i <= rnum; i++){
441     char buf[RECBUFSIZ];
442     int len = sprintf(buf, "%08d", i);
443     if(as){
444       if(!tchdbputasync(hdb, buf, len, buf, len)){
445         eprint(hdb, "tchdbput");
446         err = true;
447         break;
448       }
449     } else {
450       if(!tchdbput(hdb, buf, len, buf, len)){
451         eprint(hdb, "tchdbput");
452         err = true;
453         break;
454       }
455     }
456     if(rnum > 250 && i % (rnum / 250) == 0){
457       putchar('.');
458       fflush(stdout);
459       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
460     }
461   }
462   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
463   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
464   mprint(hdb);
465   if(!tchdbclose(hdb)){
466     eprint(hdb, "tchdbclose");
467     err = true;
468   }
469   tchdbdel(hdb);
470   iprintf("time: %.3f\n", tctime() - stime);
471   iprintf("%s\n\n", err ? "error" : "ok");
472   return err ? 1 : 0;
473 }
474
475
476 /* perform read command */
477 static int procread(const char *path, bool mt, int rcnum, int omode, bool wb){
478   iprintf("<Reading Test>\n  path=%s  mt=%d  rcnum=%d  omode=%d  wb=%d\n",
479           path, mt, rcnum, omode, wb);
480   bool err = false;
481   double stime = tctime();
482   TCHDB *hdb = tchdbnew();
483   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
484   if(mt && !tchdbsetmutex(hdb)){
485     eprint(hdb, "tchdbsetmutex");
486     err = true;
487   }
488   if(!tchdbsetcache(hdb, rcnum)){
489     eprint(hdb, "tchdbsetcache");
490     err = true;
491   }
492   if(!tchdbopen(hdb, path, HDBOREADER | omode)){
493     eprint(hdb, "tchdbopen");
494     err = true;
495   }
496   int rnum = tchdbrnum(hdb);
497   for(int i = 1; i <= rnum; i++){
498     char kbuf[RECBUFSIZ];
499     int ksiz = sprintf(kbuf, "%08d", i);
500     int vsiz;
501     if(wb){
502       char vbuf[RECBUFSIZ];
503       int vsiz = tchdbget3(hdb, kbuf, ksiz, vbuf, RECBUFSIZ);
504       if(vsiz < 0){
505         eprint(hdb, "tchdbget3");
506         err = true;
507         break;
508       }
509     } else {
510       char *vbuf = tchdbget(hdb, kbuf, ksiz, &vsiz);
511       if(!vbuf){
512         eprint(hdb, "tchdbget");
513         err = true;
514         break;
515       }
516       free(vbuf);
517     }
518     if(rnum > 250 && i % (rnum / 250) == 0){
519       putchar('.');
520       fflush(stdout);
521       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
522     }
523   }
524   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
525   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
526   mprint(hdb);
527   if(!tchdbclose(hdb)){
528     eprint(hdb, "tchdbclose");
529     err = true;
530   }
531   tchdbdel(hdb);
532   iprintf("time: %.3f\n", tctime() - stime);
533   iprintf("%s\n\n", err ? "error" : "ok");
534   return err ? 1 : 0;
535 }
536
537
538 /* perform remove command */
539 static int procremove(const char *path, bool mt, int rcnum, int omode){
540   iprintf("<Removing Test>\n  path=%s  mt=%d  rcnum=%d  omode=%d\n", path, mt, rcnum, omode);
541   bool err = false;
542   double stime = tctime();
543   TCHDB *hdb = tchdbnew();
544   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
545   if(mt && !tchdbsetmutex(hdb)){
546     eprint(hdb, "tchdbsetmutex");
547     err = true;
548   }
549   if(!tchdbsetcache(hdb, rcnum)){
550     eprint(hdb, "tchdbsetcache");
551     err = true;
552   }
553   if(!tchdbopen(hdb, path, HDBOWRITER | omode)){
554     eprint(hdb, "tchdbopen");
555     err = true;
556   }
557   int rnum = tchdbrnum(hdb);
558   for(int i = 1; i <= rnum; i++){
559     char kbuf[RECBUFSIZ];
560     int ksiz = sprintf(kbuf, "%08d", i);
561     if(!tchdbout(hdb, kbuf, ksiz)){
562       eprint(hdb, "tchdbout");
563       err = true;
564       break;
565     }
566     if(rnum > 250 && i % (rnum / 250) == 0){
567       putchar('.');
568       fflush(stdout);
569       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
570     }
571   }
572   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
573   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
574   mprint(hdb);
575   if(!tchdbclose(hdb)){
576     eprint(hdb, "tchdbclose");
577     err = true;
578   }
579   tchdbdel(hdb);
580   iprintf("time: %.3f\n", tctime() - stime);
581   iprintf("%s\n\n", err ? "error" : "ok");
582   return err ? 1 : 0;
583 }
584
585
586 /* perform rcat command */
587 static int procrcat(const char *path, int rnum, int bnum, int apow, int fpow,
588                     bool mt, int opts, int rcnum, int omode, int pnum, bool rl){
589   iprintf("<Random Concatenating Test>\n"
590           "  path=%s  rnum=%d  bnum=%d  apow=%d  fpow=%d  mt=%d  opts=%d  rcnum=%d"
591           "  omode=%d  pnum=%d  rl=%d\n\n",
592           path, rnum, bnum, apow, fpow, mt, opts, rcnum, omode, pnum, rl);
593   if(pnum < 1) pnum = rnum;
594   bool err = false;
595   double stime = tctime();
596   TCHDB *hdb = tchdbnew();
597   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
598   if(mt && !tchdbsetmutex(hdb)){
599     eprint(hdb, "tchdbsetmutex");
600     err = true;
601   }
602   if(!tchdbtune(hdb, bnum, apow, fpow, opts)){
603     eprint(hdb, "tchdbtune");
604     err = true;
605   }
606   if(!tchdbsetcache(hdb, rcnum)){
607     eprint(hdb, "tchdbsetcache");
608     err = true;
609   }
610   if(!tchdbopen(hdb, path, HDBOWRITER | HDBOCREAT | HDBOTRUNC | omode)){
611     eprint(hdb, "tchdbopen");
612     err = true;
613   }
614   for(int i = 1; i <= rnum; i++){
615     char kbuf[RECBUFSIZ];
616     int ksiz = sprintf(kbuf, "%d", myrand(pnum));
617     if(rl){
618       char vbuf[PATH_MAX];
619       int vsiz = myrand(PATH_MAX);
620       for(int j = 0; j < vsiz; j++){
621         vbuf[j] = myrand(0x100);
622       }
623       if(!tchdbputcat(hdb, kbuf, ksiz, vbuf, vsiz)){
624         eprint(hdb, "tchdbputcat");
625         err = true;
626         break;
627       }
628     } else {
629       if(!tchdbputcat(hdb, kbuf, ksiz, kbuf, ksiz)){
630         eprint(hdb, "tchdbputcat");
631         err = true;
632         break;
633       }
634     }
635     if(rnum > 250 && i % (rnum / 250) == 0){
636       putchar('.');
637       fflush(stdout);
638       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
639     }
640   }
641   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
642   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
643   mprint(hdb);
644   if(!tchdbclose(hdb)){
645     eprint(hdb, "tchdbclose");
646     err = true;
647   }
648   tchdbdel(hdb);
649   iprintf("time: %.3f\n", tctime() - stime);
650   iprintf("%s\n\n", err ? "error" : "ok");
651   return err ? 1 : 0;
652 }
653
654
655 /* perform misc command */
656 static int procmisc(const char *path, int rnum, bool mt, int opts, int omode){
657   iprintf("<Miscellaneous Test>\n  path=%s  rnum=%d  mt=%d  opts=%d  omode=%d\n\n",
658           path, rnum, mt, opts, omode);
659   bool err = false;
660   double stime = tctime();
661   TCHDB *hdb = tchdbnew();
662   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
663   if(mt && !tchdbsetmutex(hdb)){
664     eprint(hdb, "tchdbsetmutex");
665     err = true;
666   }
667   if(!tchdbtune(hdb, rnum / 50, 2, -1, opts)){
668     eprint(hdb, "tchdbtune");
669     err = true;
670   }
671   if(!tchdbsetcache(hdb, rnum / 10)){
672     eprint(hdb, "tchdbsetcache");
673     err = true;
674   }
675   if(!tchdbopen(hdb, path, HDBOWRITER | HDBOCREAT | HDBOTRUNC | omode)){
676     eprint(hdb, "tchdbopen");
677     err = true;
678   }
679   iprintf("writing:\n");
680   for(int i = 1; i <= rnum; i++){
681     char buf[RECBUFSIZ];
682     int len = sprintf(buf, "%08d", i);
683     if(i % 3 == 0){
684       if(!tchdbputkeep(hdb, buf, len, buf, len)){
685         eprint(hdb, "tchdbputkeep");
686         err = true;
687         break;
688       }
689     } else {
690       if(!tchdbputasync(hdb, buf, len, buf, len)){
691         eprint(hdb, "tchdbputasync");
692         err = true;
693         break;
694       }
695     }
696     if(rnum > 250 && i % (rnum / 250) == 0){
697       putchar('.');
698       fflush(stdout);
699       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
700     }
701   }
702   iprintf("reading:\n");
703   for(int i = 1; i <= rnum; i++){
704     char kbuf[RECBUFSIZ];
705     int ksiz = sprintf(kbuf, "%08d", i);
706     int vsiz;
707     char *vbuf = tchdbget(hdb, kbuf, ksiz, &vsiz);
708     if(!vbuf){
709       eprint(hdb, "tchdbget");
710       err = true;
711       break;
712     } else if(vsiz != ksiz || memcmp(vbuf, kbuf, vsiz)){
713       eprint(hdb, "(validation)");
714       err = true;
715       free(vbuf);
716       break;
717     }
718     free(vbuf);
719     if(rnum > 250 && i % (rnum / 250) == 0){
720       putchar('.');
721       fflush(stdout);
722       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
723     }
724   }
725   if(tchdbrnum(hdb) != rnum){
726     eprint(hdb, "(validation)");
727     err = true;
728   }
729   iprintf("random writing:\n");
730   for(int i = 1; i <= rnum; i++){
731     char kbuf[RECBUFSIZ];
732     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
733     char vbuf[RECBUFSIZ];
734     int vsiz = myrand(RECBUFSIZ);
735     memset(vbuf, '*', vsiz);
736     if(!tchdbput(hdb, kbuf, ksiz, vbuf, vsiz)){
737       eprint(hdb, "tchdbput");
738       err = true;
739       break;
740     }
741     int rsiz;
742     char *rbuf = tchdbget(hdb, kbuf, ksiz, &rsiz);
743     if(!rbuf){
744       eprint(hdb, "tchdbget");
745       err = true;
746       break;
747     }
748     if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
749       eprint(hdb, "(validation)");
750       err = true;
751       free(rbuf);
752       break;
753     }
754     if(rnum > 250 && i % (rnum / 250) == 0){
755       putchar('.');
756       fflush(stdout);
757       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
758     }
759     free(rbuf);
760   }
761   iprintf("word writing:\n");
762   const char *words[] = {
763     "a", "A", "bb", "BB", "ccc", "CCC", "dddd", "DDDD", "eeeee", "EEEEEE",
764     "mikio", "hirabayashi", "tokyo", "cabinet", "hyper", "estraier", "19780211", "birth day",
765     "one", "first", "two", "second", "three", "third", "four", "fourth", "five", "fifth",
766     "_[1]_", "uno", "_[2]_", "dos", "_[3]_", "tres", "_[4]_", "cuatro", "_[5]_", "cinco",
767     "[\xe5\xb9\xb3\xe6\x9e\x97\xe5\xb9\xb9\xe9\x9b\x84]", "[\xe9\xa6\xac\xe9\xb9\xbf]", NULL
768   };
769   for(int i = 0; words[i] != NULL; i += 2){
770     const char *kbuf = words[i];
771     int ksiz = strlen(kbuf);
772     const char *vbuf = words[i+1];
773     int vsiz = strlen(vbuf);
774     if(!tchdbputkeep(hdb, kbuf, ksiz, vbuf, vsiz)){
775       eprint(hdb, "tchdbputkeep");
776       err = true;
777       break;
778     }
779     if(rnum > 250) putchar('.');
780   }
781   if(rnum > 250) iprintf(" (%08d)\n", sizeof(words) / sizeof(*words));
782   iprintf("random erasing:\n");
783   for(int i = 1; i <= rnum; i++){
784     char kbuf[RECBUFSIZ];
785     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
786     if(!tchdbout(hdb, kbuf, ksiz) && tchdbecode(hdb) != TCENOREC){
787       eprint(hdb, "tchdbout");
788       err = true;
789       break;
790     }
791     if(rnum > 250 && i % (rnum / 250) == 0){
792       putchar('.');
793       fflush(stdout);
794       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
795     }
796   }
797   iprintf("writing:\n");
798   for(int i = 1; i <= rnum; i++){
799     char kbuf[RECBUFSIZ];
800     int ksiz = sprintf(kbuf, "[%d]", i);
801     char vbuf[RECBUFSIZ];
802     int vsiz = i % RECBUFSIZ;
803     memset(vbuf, '*', vsiz);
804     if(!tchdbputkeep(hdb, kbuf, ksiz, vbuf, vsiz)){
805       eprint(hdb, "tchdbputkeep");
806       err = true;
807       break;
808     }
809     if(vsiz < 1){
810       char tbuf[PATH_MAX];
811       for(int j = 0; j < PATH_MAX; j++){
812         tbuf[j] = myrand(0x100);
813       }
814       if(!tchdbput(hdb, kbuf, ksiz, tbuf, PATH_MAX)){
815         eprint(hdb, "tchdbput");
816         err = true;
817         break;
818       }
819     }
820     if(rnum > 250 && i % (rnum / 250) == 0){
821       putchar('.');
822       fflush(stdout);
823       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
824     }
825   }
826   iprintf("erasing:\n");
827   for(int i = 1; i <= rnum; i++){
828     if(i % 2 == 1){
829       char kbuf[RECBUFSIZ];
830       int ksiz = sprintf(kbuf, "[%d]", i);
831       if(!tchdbout(hdb, kbuf, ksiz)){
832         eprint(hdb, "tchdbout");
833         err = true;
834         break;
835       }
836       if(tchdbout(hdb, kbuf, ksiz) || tchdbecode(hdb) != TCENOREC){
837         eprint(hdb, "tchdbout");
838         err = true;
839         break;
840       }
841     }
842     if(rnum > 250 && i % (rnum / 250) == 0){
843       putchar('.');
844       fflush(stdout);
845       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
846     }
847   }
848   iprintf("random writing and reopening:\n");
849   for(int i = 1; i <= rnum; i++){
850     if(myrand(10) == 0){
851       int ksiz, vsiz;
852       char *kbuf, *vbuf;
853       ksiz = (myrand(5) == 0) ? myrand(UINT16_MAX) : myrand(RECBUFSIZ);
854       kbuf = tcmalloc(ksiz + 1);
855       memset(kbuf, '@', ksiz);
856       vsiz = (myrand(5) == 0) ? myrand(UINT16_MAX) : myrand(RECBUFSIZ);
857       vbuf = tcmalloc(vsiz + 1);
858       for(int j = 0; j < vsiz; j++){
859         vbuf[j] = myrand(256);
860       }
861       switch(myrand(4)){
862       case 0:
863         if(!tchdbput(hdb, kbuf, ksiz, vbuf, vsiz)){
864           eprint(hdb, "tchdbput");
865           err = true;
866         }
867         break;
868       case 1:
869         if(!tchdbputcat(hdb, kbuf, ksiz, vbuf, vsiz)){
870           eprint(hdb, "tchdbputcat");
871           err = true;
872         }
873         break;
874       case 2:
875         if(!tchdbputasync(hdb, kbuf, ksiz, vbuf, vsiz)){
876           eprint(hdb, "tchdbputasync");
877           err = true;
878         }
879         break;
880       case 3:
881         if(!tchdbout(hdb, kbuf, ksiz) && tchdbecode(hdb) != TCENOREC){
882           eprint(hdb, "tchdbout");
883           err = true;
884         }
885         break;
886       }
887       free(vbuf);
888       free(kbuf);
889     } else {
890       char kbuf[RECBUFSIZ];
891       int ksiz = myrand(RECBUFSIZ);
892       memset(kbuf, '@', ksiz);
893       char vbuf[RECBUFSIZ];
894       int vsiz = myrand(RECBUFSIZ);
895       memset(vbuf, '@', vsiz);
896       if(!tchdbput(hdb, kbuf, ksiz, vbuf, vsiz)){
897         eprint(hdb, "tchdbputcat");
898         err = true;
899         break;
900       }
901     }
902     if(rnum > 250 && i % (rnum / 250) == 0){
903       putchar('.');
904       fflush(stdout);
905       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
906     }
907   }
908   if(!tchdbclose(hdb)){
909     eprint(hdb, "tchdbclose");
910     err = true;
911   }
912   if(!tchdbopen(hdb, path, HDBOWRITER | omode)){
913     eprint(hdb, "tchdbopen");
914     err = true;
915   }
916   iprintf("checking:\n");
917   for(int i = 1; i <= rnum; i++){
918     char kbuf[RECBUFSIZ];
919     int ksiz = sprintf(kbuf, "[%d]", i);
920     int vsiz;
921     char *vbuf = tchdbget(hdb, kbuf, ksiz, &vsiz);
922     if(i % 2 == 0){
923       if(!vbuf){
924         eprint(hdb, "tchdbget");
925         err = true;
926         break;
927       }
928       if(vsiz != i % RECBUFSIZ && vsiz != PATH_MAX){
929         eprint(hdb, "(validation)");
930         err = true;
931         free(vbuf);
932         break;
933       }
934     } else {
935       if(vbuf || tchdbecode(hdb) != TCENOREC){
936         eprint(hdb, "(validation)");
937         err = true;
938         free(vbuf);
939         break;
940       }
941     }
942     free(vbuf);
943     if(rnum > 250 && i % (rnum / 250) == 0){
944       putchar('.');
945       fflush(stdout);
946       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
947     }
948   }
949   iprintf("writing:\n");
950   for(int i = 1; i <= rnum; i++){
951     char buf[RECBUFSIZ];
952     int len = sprintf(buf, "%08d", i);
953     if(!tchdbput(hdb, buf, len, buf, len)){
954       eprint(hdb, "tchdbput");
955       err = true;
956       break;
957     }
958     if(rnum > 250 && i % (rnum / 250) == 0){
959       putchar('.');
960       fflush(stdout);
961       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
962     }
963   }
964   iprintf("reading:\n");
965   for(int i = 1; i <= rnum; i++){
966     char kbuf[RECBUFSIZ];
967     int ksiz = sprintf(kbuf, "%08d", i);
968     int vsiz;
969     char *vbuf = tchdbget(hdb, kbuf, ksiz, &vsiz);
970     if(!vbuf){
971       eprint(hdb, "tchdbget");
972       err = true;
973       break;
974     } else if(vsiz != ksiz || memcmp(vbuf, kbuf, vsiz)){
975       eprint(hdb, "(validation)");
976       err = true;
977       free(vbuf);
978       break;
979     }
980     free(vbuf);
981     if(rnum > 250 && i % (rnum / 250) == 0){
982       putchar('.');
983       fflush(stdout);
984       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
985     }
986   }
987   iprintf("word checking:\n");
988   for(int i = 0; words[i] != NULL; i += 2){
989     const char *kbuf = words[i];
990     int ksiz = strlen(kbuf);
991     const char *vbuf = words[i+1];
992     int vsiz = strlen(vbuf);
993     int rsiz;
994     char *rbuf = tchdbget(hdb, kbuf, ksiz, &rsiz);
995     if(!rbuf){
996       eprint(hdb, "tchdbget");
997       err = true;
998       break;
999     } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1000       eprint(hdb, "(validation)");
1001       err = true;
1002       free(rbuf);
1003       break;
1004     }
1005     free(rbuf);
1006     if(rnum > 250) putchar('.');
1007   }
1008   if(rnum > 250) iprintf(" (%08d)\n", sizeof(words) / sizeof(*words));
1009   iprintf("iterator checking:\n");
1010   if(!tchdbiterinit(hdb)){
1011     eprint(hdb, "tchdbiterinit");
1012     err = true;
1013   }
1014   char *kbuf;
1015   int ksiz;
1016   int inum = 0;
1017   for(int i = 1; (kbuf = tchdbiternext(hdb, &ksiz)) != NULL; i++, inum++){
1018     int vsiz;
1019     char *vbuf = tchdbget(hdb, kbuf, ksiz, &vsiz);
1020     if(!vbuf){
1021       eprint(hdb, "tchdbget");
1022       err = true;
1023       free(kbuf);
1024       break;
1025     }
1026     free(vbuf);
1027     free(kbuf);
1028     if(rnum > 250 && i % (rnum / 250) == 0){
1029       putchar('.');
1030       fflush(stdout);
1031       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1032     }
1033   }
1034   if(rnum > 250) iprintf(" (%08d)\n", inum);
1035   if(tchdbecode(hdb) != TCENOREC || inum != tchdbrnum(hdb)){
1036     eprint(hdb, "(validation)");
1037     err = true;
1038   }
1039   iprintf("iteration updating:\n");
1040   if(!tchdbiterinit(hdb)){
1041     eprint(hdb, "tchdbiterinit");
1042     err = true;
1043   }
1044   inum = 0;
1045   for(int i = 1; (kbuf = tchdbiternext(hdb, &ksiz)) != NULL; i++, inum++){
1046     if(myrand(2) == 0){
1047       if(!tchdbputcat(hdb, kbuf, ksiz, "0123456789", 10)){
1048         eprint(hdb, "tchdbputcat");
1049         err = true;
1050         free(kbuf);
1051         break;
1052       }
1053     } else {
1054       if(!tchdbout(hdb, kbuf, ksiz)){
1055         eprint(hdb, "tchdbout");
1056         err = true;
1057         free(kbuf);
1058         break;
1059       }
1060     }
1061     free(kbuf);
1062     if(rnum > 250 && i % (rnum / 250) == 0){
1063       putchar('.');
1064       fflush(stdout);
1065       if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
1066     }
1067   }
1068   if(rnum > 250) iprintf(" (%08d)\n", inum);
1069   if(tchdbecode(hdb) != TCENOREC || inum < tchdbrnum(hdb)){
1070     eprint(hdb, "(validation)");
1071     err = true;
1072   }
1073   if(!tchdbsync(hdb)){
1074     eprint(hdb, "tchdbsync");
1075     err = true;
1076   }
1077   if(!tchdbvanish(hdb)){
1078     eprint(hdb, "tchdbvanish");
1079     err = true;
1080   }
1081   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
1082   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
1083   mprint(hdb);
1084   if(!tchdbclose(hdb)){
1085     eprint(hdb, "tchdbclose");
1086     err = true;
1087   }
1088   tchdbdel(hdb);
1089   iprintf("time: %.3f\n", tctime() - stime);
1090   iprintf("%s\n\n", err ? "error" : "ok");
1091   return err ? 1 : 0;
1092 }
1093
1094
1095 /* perform wicked command */
1096 static int procwicked(const char *path, int rnum, bool mt, int opts, int omode){
1097   iprintf("<Wicked Writing Test>\n  path=%s  rnum=%d  mt=%d  opts=%d  omode=%d\n\n",
1098           path, rnum, mt, opts, omode);
1099   bool err = false;
1100   double stime = tctime();
1101   TCHDB *hdb = tchdbnew();
1102   if(g_dbgfd >= 0) tchdbsetdbgfd(hdb, g_dbgfd);
1103   if(mt && !tchdbsetmutex(hdb)){
1104     eprint(hdb, "tchdbsetmutex");
1105     err = true;
1106   }
1107   if(!tchdbtune(hdb, rnum / 50, 2, -1, opts)){
1108     eprint(hdb, "tchdbtune");
1109     err = true;
1110   }
1111   if(!tchdbsetcache(hdb, rnum / 10)){
1112     eprint(hdb, "tchdbsetcache");
1113     err = true;
1114   }
1115   if(!tchdbopen(hdb, path, HDBOWRITER | HDBOCREAT | HDBOTRUNC | omode)){
1116     eprint(hdb, "tchdbopen");
1117     err = true;
1118   }
1119   if(!tchdbiterinit(hdb)){
1120     eprint(hdb, "tchdbiterinit");
1121     err = true;
1122   }
1123   TCMAP *map = tcmapnew2(rnum / 5);
1124   for(int i = 1; i <= rnum && !err; i++){
1125     char kbuf[RECBUFSIZ];
1126     int ksiz = sprintf(kbuf, "%d", myrand(rnum));
1127     char vbuf[RECBUFSIZ];
1128     int vsiz = myrand(RECBUFSIZ);
1129     memset(vbuf, '*', vsiz);
1130     vbuf[vsiz] = '\0';
1131     char *rbuf;
1132     switch(myrand(16)){
1133     case 0:
1134       putchar('0');
1135       if(!tchdbput(hdb, kbuf, ksiz, vbuf, vsiz)){
1136         eprint(hdb, "tchdbput");
1137         err = true;
1138       }
1139       tcmapput(map, kbuf, ksiz, vbuf, vsiz);
1140       break;
1141     case 1:
1142       putchar('1');
1143       if(!tchdbput2(hdb, kbuf, vbuf)){
1144         eprint(hdb, "tchdbput2");
1145         err = true;
1146       }
1147       tcmapput2(map, kbuf, vbuf);
1148       break;
1149     case 2:
1150       putchar('2');
1151       if(!tchdbputkeep(hdb, kbuf, ksiz, vbuf, vsiz) && tchdbecode(hdb) != TCEKEEP){
1152         eprint(hdb, "tchdbputkeep");
1153         err = true;
1154       }
1155       tcmapputkeep(map, kbuf, ksiz, vbuf, vsiz);
1156       break;
1157     case 3:
1158       putchar('3');
1159       if(!tchdbputkeep2(hdb, kbuf, vbuf) && tchdbecode(hdb) != TCEKEEP){
1160         eprint(hdb, "tchdbputkeep2");
1161         err = true;
1162       }
1163       tcmapputkeep2(map, kbuf, vbuf);
1164       break;
1165     case 4:
1166       putchar('4');
1167       if(!tchdbputcat(hdb, kbuf, ksiz, vbuf, vsiz)){
1168         eprint(hdb, "tchdbputcat");
1169         err = true;
1170       }
1171       tcmapputcat(map, kbuf, ksiz, vbuf, vsiz);
1172       break;
1173     case 5:
1174       putchar('5');
1175       if(!tchdbputcat2(hdb, kbuf, vbuf)){
1176         eprint(hdb, "tchdbputcat2");
1177         err = true;
1178       }
1179       tcmapputcat2(map, kbuf, vbuf);
1180       break;
1181     case 6:
1182       putchar('6');
1183       if(!tchdbputasync(hdb, kbuf, ksiz, vbuf, vsiz)){
1184         eprint(hdb, "tchdbputasync");
1185         err = true;
1186       }
1187       tcmapput(map, kbuf, ksiz, vbuf, vsiz);
1188       break;
1189     case 7:
1190       putchar('7');
1191       if(!tchdbputasync2(hdb, kbuf, vbuf)){
1192         eprint(hdb, "tchdbputasync2");
1193         err = true;
1194       }
1195       tcmapput2(map, kbuf, vbuf);
1196       break;
1197     case 8:
1198       putchar('8');
1199       if(myrand(10) == 0){
1200         if(!tchdbout(hdb, kbuf, ksiz) && tchdbecode(hdb) != TCENOREC){
1201           eprint(hdb, "tchdbout");
1202           err = true;
1203         }
1204         tcmapout(map, kbuf, ksiz);
1205       }
1206       break;
1207     case 9:
1208       putchar('9');
1209       if(myrand(10) == 0){
1210         if(!tchdbout2(hdb, kbuf) && tchdbecode(hdb) != TCENOREC){
1211           eprint(hdb, "tchdbout2");
1212           err = true;
1213         }
1214         tcmapout2(map, kbuf);
1215       }
1216       break;
1217     case 10:
1218       putchar('A');
1219       if(!(rbuf = tchdbget(hdb, kbuf, ksiz, &vsiz))){
1220         if(tchdbecode(hdb) != TCENOREC){
1221           eprint(hdb, "tchdbget");
1222           err = true;
1223         }
1224         rbuf = tcsprintf("[%d]", myrand(i + 1));
1225         vsiz = strlen(rbuf);
1226       }
1227       vsiz += myrand(vsiz);
1228       if(myrand(3) == 0) vsiz += PATH_MAX;
1229       rbuf = tcrealloc(rbuf, vsiz + 1);
1230       for(int j = 0; j < vsiz; j++){
1231         rbuf[j] = myrand(0x100);
1232       }
1233       if(!tchdbput(hdb, kbuf, ksiz, rbuf, vsiz)){
1234         eprint(hdb, "tchdbput");
1235         err = true;
1236       }
1237       tcmapput(map, kbuf, ksiz, rbuf, vsiz);
1238       free(rbuf);
1239       break;
1240     case 11:
1241       putchar('B');
1242       if(!(rbuf = tchdbget(hdb, kbuf, ksiz, &vsiz)) && tchdbecode(hdb) != TCENOREC){
1243         eprint(hdb, "tchdbget");
1244         err = true;
1245       }
1246       free(rbuf);
1247       break;
1248     case 12:
1249       putchar('C');
1250       if(!(rbuf = tchdbget2(hdb, kbuf)) && tchdbecode(hdb) != TCENOREC){
1251         eprint(hdb, "tchdbget");
1252         err = true;
1253       }
1254       free(rbuf);
1255       break;
1256     case 13:
1257       putchar('D');
1258       if(myrand(1) == 0) vsiz = 1;
1259       if((vsiz = tchdbget3(hdb, kbuf, ksiz, vbuf, vsiz)) < 0 && tchdbecode(hdb) != TCENOREC){
1260         eprint(hdb, "tchdbget");
1261         err = true;
1262       }
1263       break;
1264     case 14:
1265       putchar('E');
1266       if(myrand(rnum / 50) == 0){
1267         if(!tchdbiterinit(hdb)){
1268           eprint(hdb, "tchdbiterinit");
1269           err = true;
1270         }
1271       }
1272       TCXSTR *ikey = tcxstrnew();
1273       TCXSTR *ival = tcxstrnew();
1274       for(int j = myrand(rnum) / 1000 + 1; j >= 0; j--){
1275         if(j % 3 == 0){
1276           if(tchdbiternext3(hdb, ikey, ival)){
1277             if(tcxstrsize(ival) != tchdbvsiz(hdb, tcxstrptr(ikey), tcxstrsize(ikey))){
1278               eprint(hdb, "(validation)");
1279               err = true;
1280             }
1281           } else {
1282             int ecode = tchdbecode(hdb);
1283             if(ecode != TCEINVALID && ecode != TCENOREC){
1284               eprint(hdb, "tchdbiternext3");
1285               err = true;
1286             }
1287           }
1288         } else {
1289           int iksiz;
1290           char *ikbuf = tchdbiternext(hdb, &iksiz);
1291           if(ikbuf){
1292             free(ikbuf);
1293           } else {
1294             int ecode = tchdbecode(hdb);
1295             if(ecode != TCEINVALID && ecode != TCENOREC){
1296               eprint(hdb, "tchdbiternext");
1297               err = true;
1298             }
1299           }
1300         }
1301       }
1302       tcxstrdel(ival);
1303       tcxstrdel(ikey);
1304       break;
1305     default:
1306       putchar('@');
1307       if(myrand(10000) == 0) srand((unsigned int)(tctime() * 1000) % UINT_MAX);
1308       if(myrand(rnum / 16 + 1) == 0){
1309         int cnt = myrand(30);
1310         for(int j = 0; j < rnum && !err; j++){
1311           ksiz = sprintf(kbuf, "%d", i + j);
1312           if(tchdbout(hdb, kbuf, ksiz)){
1313             cnt--;
1314           } else if(tchdbecode(hdb) != TCENOREC){
1315             eprint(hdb, "tcbdbout");
1316             err = true;
1317           }
1318           tcmapout(map, kbuf, ksiz);
1319           if(cnt < 0) break;
1320         }
1321       }
1322       break;
1323     }
1324     if(i % 50 == 0) iprintf(" (%08d)\n", i);
1325     if(i == rnum / 2){
1326       if(!tchdbclose(hdb)){
1327         eprint(hdb, "tchdbclose");
1328         err = true;
1329       }
1330       if(!tchdbopen(hdb, path, HDBOWRITER | omode)){
1331         eprint(hdb, "tchdbopen");
1332         err = true;
1333       }
1334     } else if(i == rnum / 4){
1335       char *npath = tcsprintf("%s-tmp", path);
1336       if(!tchdbcopy(hdb, npath)){
1337         eprint(hdb, "tchdbcopy");
1338         err = true;
1339       }
1340       TCHDB *nhdb = tchdbnew();
1341       if(!tchdbopen(nhdb, npath, HDBOREADER | omode)){
1342         eprint(nhdb, "tchdbopen");
1343         err = true;
1344       }
1345       tchdbdel(nhdb);
1346       unlink(npath);
1347       free(npath);
1348       if(!tchdboptimize(hdb, rnum / 50, -1, -1, -1)){
1349         eprint(hdb, "tchdboptimize");
1350         err = true;
1351       }
1352       if(!tchdbiterinit(hdb)){
1353         eprint(hdb, "tchdbiterinit");
1354         err = true;
1355       }
1356     }
1357   }
1358   if(rnum % 50 > 0) iprintf(" (%08d)\n", rnum);
1359   if(!tchdbsync(hdb)){
1360     eprint(hdb, "tchdbsync");
1361     err = true;
1362   }
1363   if(tchdbrnum(hdb) != tcmaprnum(map)){
1364     eprint(hdb, "(validation)");
1365     err = true;
1366   }
1367   for(int i = 1; i <= rnum && !err; i++){
1368     char kbuf[RECBUFSIZ];
1369     int ksiz = sprintf(kbuf, "%d", i - 1);
1370     int vsiz;
1371     const char *vbuf = tcmapget(map, kbuf, ksiz, &vsiz);
1372     int rsiz;
1373     char *rbuf = tchdbget(hdb, kbuf, ksiz, &rsiz);
1374     if(vbuf){
1375       putchar('.');
1376       if(!rbuf){
1377         eprint(hdb, "tchdbget");
1378         err = true;
1379       } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1380         eprint(hdb, "(validation)");
1381         err = true;
1382       }
1383     } else {
1384       putchar('*');
1385       if(rbuf || tchdbecode(hdb) != TCENOREC){
1386         eprint(hdb, "(validation)");
1387         err = true;
1388       }
1389     }
1390     free(rbuf);
1391     if(i % 50 == 0) iprintf(" (%08d)\n", i);
1392   }
1393   if(rnum % 50 > 0) iprintf(" (%08d)\n", rnum);
1394   tcmapiterinit(map);
1395   int ksiz;
1396   const char *kbuf;
1397   for(int i = 1; (kbuf = tcmapiternext(map, &ksiz)) != NULL; i++){
1398     putchar('+');
1399     int vsiz;
1400     const char *vbuf = tcmapiterval(kbuf, &vsiz);
1401     int rsiz;
1402     char *rbuf = tchdbget(hdb, kbuf, ksiz, &rsiz);
1403     if(!rbuf){
1404       eprint(hdb, "tchdbget");
1405       err = true;
1406     } else if(rsiz != vsiz || memcmp(rbuf, vbuf, rsiz)){
1407       eprint(hdb, "(validation)");
1408       err = true;
1409     }
1410     free(rbuf);
1411     if(!tchdbout(hdb, kbuf, ksiz)){
1412       eprint(hdb, "tchdbout");
1413       err = true;
1414     }
1415     if(i % 50 == 0) iprintf(" (%08d)\n", i);
1416   }
1417   int mrnum = tcmaprnum(map);
1418   if(mrnum % 50 > 0) iprintf(" (%08d)\n", mrnum);
1419   if(tchdbrnum(hdb) != 0){
1420     eprint(hdb, "(validation)");
1421     err = true;
1422   }
1423   iprintf("record number: %llu\n", (unsigned long long)tchdbrnum(hdb));
1424   iprintf("size: %llu\n", (unsigned long long)tchdbfsiz(hdb));
1425   mprint(hdb);
1426   tcmapdel(map);
1427   if(!tchdbclose(hdb)){
1428     eprint(hdb, "tchdbclose");
1429     err = true;
1430   }
1431   tchdbdel(hdb);
1432   iprintf("time: %.3f\n", tctime() - stime);
1433   iprintf("%s\n\n", err ? "error" : "ok");
1434   return err ? 1 : 0;
1435 }
1436
1437
1438
1439 // END OF FILE