1 /*************************************************************************************************
2 * The test cases of the core API
3 * Copyright (C) 2007-2010 FAL Labs
4 * This file is part of Tokyo Dystopia.
5 * Tokyo Dystopia 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 Dystopia 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 * Dystopia; 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 <dystopia.h>
18 #include "myconf.h"
19
20 #define TEXTBUFSIZ 65536 // buffer for texts
21 #define DEFAVGLEN 16 // default average text length
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(TCIDB *idb, const char *func);
34 static void sysprint(void);
35 static int myrand(int range);
36 static bool mysynccb(int total, int current, const char *msg, void *opq);
37 static void setrndtext(char *buf, int avg, int min, bool en);
38 static void setidtext(char *buf, uint64_t id, bool en);
39 static int runwrite(int argc, char **argv);
40 static int runread(int argc, char **argv);
41 static int runwicked(int argc, char **argv);
42 static int procwrite(const char *path, int rnum, int opts,
43 int64_t ernum, int64_t etnum, int64_t iusiz, int64_t icsiz, int exopts,
44 int omode, int alen, bool en);
45 static int procread(const char *path, int rnum, int omode, int alen, int mlen, bool en,
46 int smode);
47 static int procwicked(const char *path, int rnum, int opts,
48 int64_t ernum, int64_t etnum, int64_t iusiz, int64_t icsiz,
49 int omode, int alen, bool en);
50
51
52 /* main routine */
main(int argc,char ** argv)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 = tcatoi(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], "wicked")){
66 rv = runwicked(argc, argv);
67 } else {
68 usage();
69 }
70 return rv;
71 }
72
73
74 /* print the usage and exit */
usage(void)75 static void usage(void){
76 fprintf(stderr, "%s: test cases of the core API of Tokyo Dystopia\n", g_progname);
77 fprintf(stderr, "\n");
78 fprintf(stderr, "usage:\n");
79 fprintf(stderr, " %s write [-tl] [-td|-tb|-tt] [-er num] [-et num] [-iu num] [-ic num] [-xnt]"
80 " [-nl|-nb] [-la num] [-en] path rnum\n", g_progname);
81 fprintf(stderr, " %s read [-nl|-nb] [-la num] [-lm num] [-en] [-sp|-ss|-sf|-st|-stp|-sts]"
82 " path rnum\n", g_progname);
83 fprintf(stderr, " %s wicked [-tl] [-td|-tb|-tt] [-er num] [-et num] [-iu num] [-ic num]"
84 " [-nl|-nb] [-la num] [-en] path rnum\n", g_progname);
85 fprintf(stderr, "\n");
86 exit(1);
87 }
88
89
90 /* print formatted information string and flush the buffer */
iprintf(const char * format,...)91 static void iprintf(const char *format, ...){
92 va_list ap;
93 va_start(ap, format);
94 vprintf(format, ap);
95 fflush(stdout);
96 va_end(ap);
97 }
98
99
100 /* print error message of hash database */
eprint(TCIDB * idb,const char * func)101 static void eprint(TCIDB *idb, const char *func){
102 const char *path = tcidbpath(idb);
103 int ecode = tcidbecode(idb);
104 fprintf(stderr, "%s: %s: %s: error: %d: %s\n",
105 g_progname, path ? path : "-", func, ecode, tcidberrmsg(ecode));
106 }
107
108
109 /* print system information */
sysprint(void)110 static void sysprint(void){
111 TCMAP *info = tcsysinfo();
112 if(info){
113 tcmapiterinit(info);
114 const char *kbuf;
115 while((kbuf = tcmapiternext2(info)) != NULL){
116 iprintf("sys_%s: %s\n", kbuf, tcmapiterval2(kbuf));
117 }
118 tcmapdel(info);
119 }
120 }
121
122
123 /* get a random number */
myrand(int range)124 static int myrand(int range){
125 return (int)((double)range * rand() / (RAND_MAX + 1.0));
126 }
127
128
129 /* callback function for sync progression */
mysynccb(int total,int current,const char * msg,void * opq)130 static bool mysynccb(int total, int current, const char *msg, void *opq){
131 if(total < 10 || current % (total / 10) == 0) printf("[sync:%d:%d:%s]\n", total, current, msg);
132 return true;
133 }
134
135
136 /* fill a record buffer */
setrndtext(char * buf,int avg,int min,bool en)137 static void setrndtext(char *buf, int avg, int min, bool en){
138 int len = myrand(avg * 2);
139 if(len < 3 || len > myrand(avg * 2) + 1) len = myrand(avg + 1);
140 if(len < 2) len = myrand(avg + 1);
141 len = tclmax(min, tclmin(len, TEXTBUFSIZ - 1));
142 if(en){
143 char *wp = buf;
144 if(len > 0){
145 if(myrand(4) == 0){
146 *(wp++) = 'A' + myrand('Z' - 'A' + 1);
147 } else {
148 *(wp++) = 'a' + myrand('z' - 'a' + 1);
149 }
150 len--;
151 }
152 for(int i = 0; i < len; i++){
153 if(myrand(8) == 0){
154 *(wp++) = ' ';
155 } else if(myrand(avg + 1) == 0){
156 if(myrand(2) == 0){
157 *(wp++) = 'A' + myrand('Z' - 'A' + 1);
158 } else {
159 *(wp++) = '0' + myrand('9' - '0' + 1);
160 }
161 } else {
162 *(wp++) = 'a' + myrand('z' - 'a' + 1);
163 }
164 }
165 *wp = '\0';
166 } else {
167 uint16_t ary[TEXTBUFSIZ];
168 len = tclmin(len, TEXTBUFSIZ / 4 - 1);
169 for(int i = 0; i < len; i++){
170 ary[i] = myrand(UINT16_MAX) / (myrand(UINT8_MAX) + 1);
171 }
172 tcstrucstoutf(ary, len, buf);
173 }
174 }
175
176
177 /* fill a record buffer corresponding to an ID number */
setidtext(char * buf,uint64_t id,bool en)178 static void setidtext(char *buf, uint64_t id, bool en){
179 unsigned int tid = (unsigned int)id;
180 id += rand_r(&tid);
181 int len = (((rand_r(&tid) ^ rand_r(&tid)) >> 4) & 0x1f) + 1;
182 if(en){
183 char *tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+ ";
184 char *wp = buf;
185 for(int i = 0; i < len; i++){
186 *(wp++) = tbl[id&0x3f];
187 id >>= 4;
188 if(id < 1) id = rand_r(&tid);
189 }
190 *wp = '\0';
191 } else {
192 uint16_t ary[TEXTBUFSIZ];
193 len = tclmin(len, TEXTBUFSIZ / 4 - 1);
194 for(int i = 0; i < len; i++){
195 ary[i] = (rand_r(&tid) >> 4) & UINT16_MAX;
196 }
197 tcstrucstoutf(ary, len, buf);
198 }
199 }
200
201
202 /* parse arguments of write command */
runwrite(int argc,char ** argv)203 static int runwrite(int argc, char **argv){
204 char *path = NULL;
205 char *rstr = NULL;
206 int opts = 0;
207 int64_t ernum = 0;
208 int64_t etnum = 0;
209 int64_t iusiz = 0;
210 int64_t icsiz = 0;
211 int exopts = 0;
212 int omode = 0;
213 int alen = DEFAVGLEN;
214 bool en = false;
215 for(int i = 2; i < argc; i++){
216 if(!path && argv[i][0] == '-'){
217 if(!strcmp(argv[i], "-tl")){
218 opts |= IDBTLARGE;
219 } else if(!strcmp(argv[i], "-td")){
220 opts |= IDBTDEFLATE;
221 } else if(!strcmp(argv[i], "-tb")){
222 opts |= IDBTBZIP;
223 } else if(!strcmp(argv[i], "-tt")){
224 opts |= IDBTTCBS;
225 } else if(!strcmp(argv[i], "-er")){
226 if(++i >= argc) usage();
227 ernum = tcatoix(argv[i]);
228 } else if(!strcmp(argv[i], "-et")){
229 if(++i >= argc) usage();
230 etnum = tcatoix(argv[i]);
231 } else if(!strcmp(argv[i], "-iu")){
232 if(++i >= argc) usage();
233 iusiz = tcatoix(argv[i]);
234 } else if(!strcmp(argv[i], "-ic")){
235 if(++i >= argc) usage();
236 icsiz = tcatoix(argv[i]);
237 } else if(!strcmp(argv[i], "-xnt")){
238 exopts |= IDBXNOTXT;
239 } else if(!strcmp(argv[i], "-nl")){
240 omode |= IDBONOLCK;
241 } else if(!strcmp(argv[i], "-nb")){
242 omode |= IDBOLCKNB;
243 } else if(!strcmp(argv[i], "-la")){
244 if(++i >= argc) usage();
245 alen = tcatoi(argv[i]);
246 } else if(!strcmp(argv[i], "-en")){
247 en = true;
248 } else {
249 usage();
250 }
251 } else if(!path){
252 path = argv[i];
253 } else if(!rstr){
254 rstr = argv[i];
255 } else {
256 usage();
257 }
258 }
259 if(!path || !rstr) usage();
260 int rnum = tcatoi(rstr);
261 if(rnum < 1 || alen < 1) usage();
262 int rv = procwrite(path, rnum, opts, ernum, etnum, iusiz, icsiz, exopts, omode, alen, en);
263 return rv;
264 }
265
266
267 /* parse arguments of read command */
runread(int argc,char ** argv)268 static int runread(int argc, char **argv){
269 char *path = NULL;
270 char *rstr = NULL;
271 int omode = 0;
272 int alen = DEFAVGLEN;
273 int mlen = 1;
274 bool en = false;
275 int smode = IDBSSUBSTR;
276 for(int i = 2; i < argc; i++){
277 if(!path && argv[i][0] == '-'){
278 if(!strcmp(argv[i], "-nl")){
279 omode |= IDBONOLCK;
280 } else if(!strcmp(argv[i], "-nb")){
281 omode |= IDBOLCKNB;
282 } else if(!strcmp(argv[i], "-la")){
283 if(++i >= argc) usage();
284 alen = tcatoi(argv[i]);
285 } else if(!strcmp(argv[i], "-lm")){
286 if(++i >= argc) usage();
287 mlen = tcatoi(argv[i]);
288 } else if(!strcmp(argv[i], "-en")){
289 en = true;
290 } else if(!strcmp(argv[i], "-sp")){
291 smode = IDBSPREFIX;
292 } else if(!strcmp(argv[i], "-ss")){
293 smode = IDBSSUFFIX;
294 } else if(!strcmp(argv[i], "-sf")){
295 smode = IDBSFULL;
296 } else if(!strcmp(argv[i], "-st")){
297 smode = IDBSTOKEN;
298 } else if(!strcmp(argv[i], "-stp")){
299 smode = IDBSTOKPRE;
300 } else if(!strcmp(argv[i], "-sts")){
301 smode = IDBSTOKSUF;
302 } else {
303 usage();
304 }
305 } else if(!path){
306 path = argv[i];
307 } else if(!rstr){
308 rstr = argv[i];
309 } else {
310 usage();
311 }
312 }
313 if(!path || !rstr) usage();
314 int rnum = tcatoi(rstr);
315 if(rnum < 1 || alen < 1 || mlen < 0) usage();
316 int rv = procread(path, rnum, omode, alen, mlen, en, smode);
317 return rv;
318 }
319
320
321 /* parse arguments of wicked command */
runwicked(int argc,char ** argv)322 static int runwicked(int argc, char **argv){
323 char *path = NULL;
324 char *rstr = NULL;
325 int opts = 0;
326 int64_t ernum = 0;
327 int64_t etnum = 0;
328 int64_t iusiz = 0;
329 int64_t icsiz = 0;
330 int omode = 0;
331 int alen = DEFAVGLEN;
332 bool en = false;
333 for(int i = 2; i < argc; i++){
334 if(!path && argv[i][0] == '-'){
335 if(!strcmp(argv[i], "-tl")){
336 opts |= IDBTLARGE;
337 } else if(!strcmp(argv[i], "-td")){
338 opts |= IDBTDEFLATE;
339 } else if(!strcmp(argv[i], "-tb")){
340 opts |= IDBTBZIP;
341 } else if(!strcmp(argv[i], "-tt")){
342 opts |= IDBTTCBS;
343 } else if(!strcmp(argv[i], "-er")){
344 if(++i >= argc) usage();
345 ernum = tcatoix(argv[i]);
346 } else if(!strcmp(argv[i], "-et")){
347 if(++i >= argc) usage();
348 etnum = tcatoix(argv[i]);
349 } else if(!strcmp(argv[i], "-iu")){
350 if(++i >= argc) usage();
351 iusiz = tcatoix(argv[i]);
352 } else if(!strcmp(argv[i], "-ic")){
353 if(++i >= argc) usage();
354 icsiz = tcatoix(argv[i]);
355 } else if(!strcmp(argv[i], "-nl")){
356 omode |= IDBONOLCK;
357 } else if(!strcmp(argv[i], "-nb")){
358 omode |= IDBOLCKNB;
359 } else if(!strcmp(argv[i], "-la")){
360 if(++i >= argc) usage();
361 alen = tcatoi(argv[i]);
362 } else if(!strcmp(argv[i], "-en")){
363 en = true;
364 } else {
365 usage();
366 }
367 } else if(!path){
368 path = argv[i];
369 } else if(!rstr){
370 rstr = argv[i];
371 } else {
372 usage();
373 }
374 }
375 if(!path || !rstr) usage();
376 int rnum = tcatoi(rstr);
377 if(rnum < 1 || alen < 1) usage();
378 int rv = procwicked(path, rnum, opts, ernum, etnum, iusiz, icsiz, omode, alen, en);
379 return rv;
380 }
381
382
383 /* perform write command */
procwrite(const char * path,int rnum,int opts,int64_t ernum,int64_t etnum,int64_t iusiz,int64_t icsiz,int exopts,int omode,int alen,bool en)384 static int procwrite(const char *path, int rnum, int opts,
385 int64_t ernum, int64_t etnum, int64_t iusiz, int64_t icsiz, int exopts,
386 int omode, int alen, bool en){
387 iprintf("<Writing Test>\n path=%s rnum=%d opts=%d ernum=%lld etnum=%lld iusiz=%lld"
388 " icsiz=%lld exopts=%d omode=%d alen=%d en=%d\n\n", path, rnum, opts,
389 (long long)ernum, (long long)etnum, (long long)iusiz, (long long)icsiz,
390 exopts, omode, alen, en);
391 bool err = false;
392 double stime = tctime();
393 TCIDB *idb = tcidbnew();
394 if(g_dbgfd >= 0) tcidbsetdbgfd(idb, g_dbgfd);
395 tcidbsetsynccb(idb, mysynccb, NULL);
396 tcidbsetexopts(idb, exopts);
397 if(!tcidbsetcache(idb, icsiz, -1)){
398 eprint(idb, "tcidbsetcache");
399 err = true;
400 }
401 if(!tcidbtune(idb, ernum, etnum, iusiz, opts)){
402 eprint(idb, "tcidbtune");
403 err = true;
404 }
405 if(!tcidbopen(idb, path, IDBOWRITER | IDBOCREAT | IDBOTRUNC | omode)){
406 eprint(idb, "tcidbopen");
407 err = true;
408 }
409 for(int i = 1; i <= rnum; i++){
410 char text[TEXTBUFSIZ];
411 setrndtext(text, alen, 1, en);
412 if(!tcidbput(idb, i, text)){
413 eprint(idb, "tcidbput");
414 err = true;
415 break;
416 }
417 if(rnum > 250 && i % (rnum / 250) == 0){
418 putchar('.');
419 fflush(stdout);
420 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
421 }
422 }
423 iprintf("record number: %llu\n", (unsigned long long)tcidbrnum(idb));
424 iprintf("size: %llu\n", (unsigned long long)tcidbfsiz(idb));
425 sysprint();
426 if(!tcidbclose(idb)){
427 eprint(idb, "tcidbclose");
428 err = true;
429 }
430 tcidbdel(idb);
431 iprintf("time: %.3f\n", tctime() - stime);
432 iprintf("%s\n\n", err ? "error" : "ok");
433 return err ? 1 : 0;
434 }
435
436
437 /* perform read command */
procread(const char * path,int rnum,int omode,int alen,int mlen,bool en,int smode)438 static int procread(const char *path, int rnum, int omode, int alen, int mlen, bool en,
439 int smode){
440 iprintf("<Reading Test>\n path=%s rnum=%d omode=%d alen=%d mlen=%d en=%d"
441 " smode=%d\n\n", path, rnum, omode, alen, mlen, en, smode);
442 bool err = false;
443 double stime = tctime();
444 TCIDB *idb = tcidbnew();
445 if(g_dbgfd >= 0) tcidbsetdbgfd(idb, g_dbgfd);
446 if(!tcidbopen(idb, path, IDBOREADER | omode)){
447 eprint(idb, "tcidbopen");
448 err = true;
449 }
450 for(int i = 1; i <= rnum; i++){
451 char text[TEXTBUFSIZ];
452 setrndtext(text, alen, mlen, en);
453 int num;
454 uint64_t *res = tcidbsearch(idb, text, smode, &num);
455 if(res){
456 tcfree(res);
457 } else {
458 eprint(idb, "tcidbsearch");
459 err = true;
460 break;
461 }
462 if(rnum > 250 && i % (rnum / 250) == 0){
463 putchar('.');
464 fflush(stdout);
465 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
466 }
467 }
468 iprintf("record number: %llu\n", (unsigned long long)tcidbrnum(idb));
469 iprintf("size: %llu\n", (unsigned long long)tcidbfsiz(idb));
470 sysprint();
471 if(!tcidbclose(idb)){
472 eprint(idb, "tcidbclose");
473 err = true;
474 }
475 tcidbdel(idb);
476 iprintf("time: %.3f\n", tctime() - stime);
477 iprintf("%s\n\n", err ? "error" : "ok");
478 return err ? 1 : 0;
479 }
480
481
482 /* perform wicked command */
procwicked(const char * path,int rnum,int opts,int64_t ernum,int64_t etnum,int64_t iusiz,int64_t icsiz,int omode,int alen,bool en)483 static int procwicked(const char *path, int rnum, int opts,
484 int64_t ernum, int64_t etnum, int64_t iusiz, int64_t icsiz,
485 int omode, int alen, bool en){
486 iprintf("<Wicked Writing Test>\n path=%s rnum=%d opts=%d ernum=%lld etnum=%lld"
487 " iusiz=%lld icsiz=%lld omode=%d alen=%d en=%d\n\n", path, rnum, opts,
488 (long long)ernum, (long long)etnum, (long long)iusiz, (long long)icsiz,
489 omode, alen, en);
490 bool err = false;
491 double stime = tctime();
492 TCIDB *idb = tcidbnew();
493 if(g_dbgfd >= 0) tcidbsetdbgfd(idb, g_dbgfd);
494 if(!tcidbtune(idb, ernum, etnum, iusiz, opts)){
495 eprint(idb, "tcidbtune");
496 err = true;
497 }
498 if(!tcidbsetcache(idb, icsiz, -1)){
499 eprint(idb, "tcidbsetcache");
500 err = true;
501 }
502 if(!tcidbopen(idb, path, IDBOWRITER | IDBOCREAT | IDBOTRUNC | omode)){
503 eprint(idb, "tcidbopen");
504 err = true;
505 }
506 int rnd = 0;
507 for(int i = 1; i <= rnum && !err; i++){
508 char text[TEXTBUFSIZ];
509 setidtext(text, i, en);
510 if(myrand(5) == 0) rnd = myrand(100);
511 if(rnd < 90){
512 putchar('P');
513 if(!tcidbput(idb, i, text)){
514 eprint(idb, "tcidbput");
515 err = true;
516 }
517 } else if(rnd < 95){
518 putchar('O');
519 if(!tcidbout(idb, i) && tcidbecode(idb) != TCENOREC){
520 eprint(idb, "tcidbout");
521 err = true;
522 }
523 } else {
524 putchar('S');
525 int num;
526 uint64_t *res = tcidbsearch(idb, text, IDBSSUBSTR, &num);
527 if(res){
528 tcfree(res);
529 } else {
530 eprint(idb, "tcidbsearch");
531 err = true;
532 }
533 }
534 if(i % 50 == 0) iprintf(" (%08d)\n", i);
535 }
536 if(rnum % 50 > 0) iprintf(" (%08d)\n", rnum);
537 iprintf("record number: %llu\n", (unsigned long long)tcidbrnum(idb));
538 iprintf("size: %llu\n", (unsigned long long)tcidbfsiz(idb));
539 sysprint();
540 if(!tcidbclose(idb)){
541 eprint(idb, "tcidbclose");
542 err = true;
543 }
544 tcidbdel(idb);
545 iprintf("time: %.3f\n", tctime() - stime);
546 iprintf("%s\n\n", err ? "error" : "ok");
547 return err ? 1 : 0;
548 }
549
550
551
552 // END OF FILE
553