1 /*************************************************************************************************
2 * The test cases of the on-memory 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 *************************************************************************************************/
20 #define RECBUFSIZ 32 // buffer for records
22 typedef struct { // type of structure for combo thread
29 typedef struct { // type of structure for typical thread
38 /* global variables */
39 const char *g_progname; // program name
42 /* function prototypes */
43 int main(int argc, char **argv);
44 static void usage(void);
45 static void iprintf(const char *format, ...);
46 static void eprint(const char *func);
47 static int myrand(int range);
48 static int myrandnd(int range);
49 static int runcombo(int argc, char **argv);
50 static int runtypical(int argc, char **argv);
51 static int proccombo(int tnum, int rnum, int bnum, bool rnd);
52 static int proctypical(int tnum, int rnum, int bnum, bool nc, int rratio);
53 static void *threadwrite(void *targ);
54 static void *threadread(void *targ);
55 static void *threadremove(void *targ);
56 static void *threadtypical(void *targ);
60 int main(int argc, char **argv){
62 srand((unsigned int)(tctime() * 1000) % UINT_MAX);
65 if(!strcmp(argv[1], "combo")){
66 rv = runcombo(argc, argv);
67 } else if(!strcmp(argv[1], "typical")){
68 rv = runtypical(argc, argv);
76 /* print the usage and exit */
77 static void usage(void){
78 fprintf(stderr, "%s: test cases of the on-memory database API of Tokyo Cabinet\n", g_progname);
79 fprintf(stderr, "\n");
80 fprintf(stderr, "usage:\n");
81 fprintf(stderr, " %s combo [-rnd] tnum rnum [bnum]\n", g_progname);
82 fprintf(stderr, " %s typical [-nc] [-rr num] tnum rnum [bnum]\n", g_progname);
83 fprintf(stderr, "\n");
88 /* print formatted information string and flush the buffer */
89 static void iprintf(const char *format, ...){
98 /* print error message of on-memory database */
99 static void eprint(const char *func){
100 fprintf(stderr, "%s: %s: error\n", g_progname, func);
104 /* get a random number */
105 static int myrand(int range){
106 return (int)((double)range * rand() / (RAND_MAX + 1.0));
110 /* get a random number based on normal distribution */
111 static int myrandnd(int range){
112 int num = (int)tcdrandnd(range >> 1, range / 10);
113 return (num < 0 || num >= range) ? 0 : num;
117 /* parse arguments of combo command */
118 static int runcombo(int argc, char **argv){
123 for(int i = 2; i < argc; i++){
124 if(!tstr && argv[i][0] == '-'){
125 if(!strcmp(argv[i], "-rnd")){
140 if(!tstr || !rstr) usage();
141 int tnum = atoi(tstr);
142 int rnum = atoi(rstr);
143 if(tnum < 1 || rnum < 1) usage();
144 int bnum = bstr ? atoi(bstr) : -1;
145 int rv = proccombo(tnum, rnum, bnum, rnd);
150 /* parse arguments of typical command */
151 static int runtypical(int argc, char **argv){
157 for(int i = 2; i < argc; i++){
158 if(!tstr && argv[i][0] == '-'){
159 if(!strcmp(argv[i], "-nc")){
161 } else if(!strcmp(argv[i], "-rr")){
162 if(++i >= argc) usage();
163 rratio = atoi(argv[i]);
177 if(!tstr || !rstr) usage();
178 int tnum = atoi(tstr);
179 int rnum = atoi(rstr);
180 if(tnum < 1 || rnum < 1) usage();
181 int bnum = bstr ? atoi(bstr) : -1;
182 int rv = proctypical(tnum, rnum, bnum, nc, rratio);
187 /* perform combo command */
188 static int proccombo(int tnum, int rnum, int bnum, bool rnd){
189 iprintf("<Combination Test>\n tnum=%d rnum=%d bnum=%d rnd=%d\n\n", tnum, rnum, bnum, rnd);
191 double stime = tctime();
192 TCMDB *mdb = (bnum > 0) ? tcmdbnew2(bnum) : tcmdbnew();
193 TARGCOMBO targs[tnum];
194 pthread_t threads[tnum];
197 targs[0].rnum = rnum;
200 if(threadwrite(targs) != NULL) err = true;
202 for(int i = 0; i < tnum; i++){
204 targs[i].rnum = rnum;
207 if(pthread_create(threads + i, NULL, threadwrite, targs + i) != 0){
208 eprint("pthread_create");
213 for(int i = 0; i < tnum; i++){
214 if(targs[i].id == -1) continue;
216 if(pthread_join(threads[i], &rv) != 0){
217 eprint("pthread_join");
226 targs[0].rnum = rnum;
229 if(threadread(targs) != NULL) err = true;
231 for(int i = 0; i < tnum; i++){
233 targs[i].rnum = rnum;
236 if(pthread_create(threads + i, NULL, threadread, targs + i) != 0){
237 eprint("pthread_create");
242 for(int i = 0; i < tnum; i++){
243 if(targs[i].id == -1) continue;
245 if(pthread_join(threads[i], &rv) != 0){
246 eprint("pthread_join");
255 targs[0].rnum = rnum;
258 if(threadremove(targs) != NULL) err = true;
260 for(int i = 0; i < tnum; i++){
262 targs[i].rnum = rnum;
265 if(pthread_create(threads + i, NULL, threadremove, targs + i) != 0){
266 eprint("pthread_create");
271 for(int i = 0; i < tnum; i++){
272 if(targs[i].id == -1) continue;
274 if(pthread_join(threads[i], &rv) != 0){
275 eprint("pthread_join");
282 iprintf("record number: %llu\n", (unsigned long long)tcmdbrnum(mdb));
284 iprintf("time: %.3f\n", tctime() - stime);
285 iprintf("%s\n\n", err ? "error" : "ok");
290 /* perform typical command */
291 static int proctypical(int tnum, int rnum, int bnum, bool nc, int rratio){
292 iprintf("<Typical Access Test>\n tnum=%d rnum=%d bnum=%d nc=%d rratio=%d\n\n",
293 tnum, rnum, bnum, nc, rratio);
295 double stime = tctime();
296 TCMDB *mdb = (bnum > 0) ? tcmdbnew2(bnum) : tcmdbnew();
297 TARGTYPICAL targs[tnum];
298 pthread_t threads[tnum];
301 targs[0].rnum = rnum;
303 targs[0].rratio = rratio;
305 if(threadtypical(targs) != NULL) err = true;
307 for(int i = 0; i < tnum; i++){
309 targs[i].rnum = rnum;
311 targs[i].rratio= rratio;
313 if(pthread_create(threads + i, NULL, threadtypical, targs + i) != 0){
314 eprint("pthread_create");
319 for(int i = 0; i < tnum; i++){
320 if(targs[i].id == -1) continue;
322 if(pthread_join(threads[i], &rv) != 0){
323 eprint("pthread_join");
330 iprintf("record number: %llu\n", (unsigned long long)tcmdbrnum(mdb));
332 iprintf("time: %.3f\n", tctime() - stime);
333 iprintf("%s\n\n", err ? "error" : "ok");
338 /* thread the write function */
339 static void *threadwrite(void *targ){
340 TCMDB *mdb = ((TARGCOMBO *)targ)->mdb;
341 int rnum = ((TARGCOMBO *)targ)->rnum;
342 bool rnd = ((TARGCOMBO *)targ)->rnd;
343 int id = ((TARGCOMBO *)targ)->id;
344 double stime = tctime();
345 if(id == 0) iprintf("writing:\n");
346 int base = id * rnum;
347 for(int i = 1; i <= rnum; i++){
349 int len = sprintf(buf, "%08d", base + (rnd ? myrand(i) : i));
350 tcmdbput(mdb, buf, len, buf, len);
351 if(id == 0 && rnum > 250 && i % (rnum / 250) == 0){
354 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
357 if(id == 0) iprintf("time: %.3f\n", tctime() - stime);
362 /* thread the read function */
363 static void *threadread(void *targ){
364 TCMDB *mdb = ((TARGCOMBO *)targ)->mdb;
365 int rnum = ((TARGCOMBO *)targ)->rnum;
366 bool rnd = ((TARGCOMBO *)targ)->rnd;
367 int id = ((TARGCOMBO *)targ)->id;
368 double stime = tctime();
369 if(id == 0) iprintf("reading:\n");
370 int base = id * rnum;
371 for(int i = 1; i <= rnum; i++){
372 char kbuf[RECBUFSIZ];
373 int ksiz = sprintf(kbuf, "%08d", base + (rnd ? myrand(i) : i));
375 char *vbuf = tcmdbget(mdb, kbuf, ksiz, &vsiz);
377 if(id == 0 && rnum > 250 && i % (rnum / 250) == 0){
380 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
383 if(id == 0) iprintf("time: %.3f\n", tctime() - stime);
388 /* thread the remove function */
389 static void *threadremove(void *targ){
390 TCMDB *mdb = ((TARGCOMBO *)targ)->mdb;
391 int rnum = ((TARGCOMBO *)targ)->rnum;
392 bool rnd = ((TARGCOMBO *)targ)->rnd;
393 int id = ((TARGCOMBO *)targ)->id;
394 double stime = tctime();
395 if(id == 0) iprintf("removing:\n");
396 int base = id * rnum;
397 for(int i = 1; i <= rnum; i++){
399 int len = sprintf(buf, "%08d", base + (rnd ? myrand(i) : i));
400 tcmdbout(mdb, buf, len);
401 if(id == 0 && rnum > 250 && i % (rnum / 250) == 0){
404 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
407 if(id == 0) iprintf("time: %.3f\n", tctime() - stime);
412 /* thread the typical function */
413 static void *threadtypical(void *targ){
414 TCMDB *mdb = ((TARGTYPICAL *)targ)->mdb;
415 int rnum = ((TARGTYPICAL *)targ)->rnum;
416 bool nc = ((TARGTYPICAL *)targ)->nc;
417 int rratio = ((TARGTYPICAL *)targ)->rratio;
418 int id = ((TARGTYPICAL *)targ)->id;
420 TCMAP *map = (!nc && id == 0) ? tcmapnew2(rnum + 1) : NULL;
421 int base = id * rnum;
422 int mrange = tclmax(50 + rratio, 100);
423 for(int i = 1; !err && i <= rnum; i++){
425 int len = sprintf(buf, "%08d", base + myrandnd(i));
426 int rnd = myrand(mrange);
428 tcmdbput(mdb, buf, len, buf, len);
429 if(map) tcmapput(map, buf, len, buf, len);
431 tcmdbputkeep(mdb, buf, len, buf, len);
432 if(map) tcmapputkeep(map, buf, len, buf, len);
434 tcmdbputcat(mdb, buf, len, buf, len);
435 if(map) tcmapputcat(map, buf, len, buf, len);
437 tcmdbout(mdb, buf, len);
438 if(map) tcmapout(map, buf, len);
440 if(myrand(10) == 0) tcmdbiterinit(mdb);
441 for(int j = 0; !err && j < 10; j++){
443 char *kbuf = tcmdbiternext(mdb, &ksiz);
448 char *vbuf = tcmdbget(mdb, buf, len, &vsiz);
452 const char *mbuf = tcmapget(map, buf, len, &msiz);
453 if(msiz != vsiz || memcmp(mbuf, vbuf, vsiz)){
454 eprint("(validation)");
460 if(map && tcmapget(map, buf, len, &vsiz)){
461 eprint("(validation)");
466 if(id == 0 && rnum > 250 && i % (rnum / 250) == 0){
469 if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
476 while(!err && (kbuf = tcmapiternext(map, &ksiz)) != NULL){
478 char *vbuf = tcmdbget(mdb, kbuf, ksiz, &vsiz);
481 const char *mbuf = tcmapget(map, kbuf, ksiz, &msiz);
482 if(!mbuf || msiz != vsiz || memcmp(mbuf, vbuf, vsiz)){
483 eprint("(validation)");
488 eprint("(validation)");
494 return err ? "error" : NULL;