1 /*************************************************************************************************
2 * The command line utility 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 *************************************************************************************************/
22 /* global variables */
23 const char *g_progname; // program name
24 int g_dbgfd; // debugging output
27 /* function prototypes */
28 int main(int argc, char **argv);
29 static void usage(void);
30 static void printerr(TCBDB *bdb);
31 static int printdata(const char *ptr, int size, bool px);
32 static char *hextoobj(const char *str, int *sp);
33 static char *mygetline(FILE *ifp);
34 static int mycmpfunc(const char *aptr, int asiz, const char *bptr, int bsiz, void *op);
35 static int runcreate(int argc, char **argv);
36 static int runinform(int argc, char **argv);
37 static int runput(int argc, char **argv);
38 static int runout(int argc, char **argv);
39 static int runget(int argc, char **argv);
40 static int runlist(int argc, char **argv);
41 static int runoptimize(int argc, char **argv);
42 static int runimporttsv(int argc, char **argv);
43 static int runversion(int argc, char **argv);
44 static int proccreate(const char *path, int lmemb, int nmemb,
45 int bnum, int apow, int fpow, BDBCMP cmp, int opts);
46 static int procinform(const char *path, int omode);
47 static int procput(const char *path, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
48 BDBCMP cmp, int omode, int dmode);
49 static int procout(const char *path, const char *kbuf, int ksiz, BDBCMP cmp, int omode);
50 static int procget(const char *path, const char *kbuf, int ksiz, BDBCMP cmp, int omode,
52 static int proclist(const char *path, BDBCMP cmp, int omode, int max, bool pv, bool px, bool bk,
53 const char *jstr, const char *bstr, const char *estr, const char *fmstr);
54 static int procoptimize(const char *path, int lmemb, int nmemb,
55 int bnum, int apow, int fpow, BDBCMP cmp, int opts, int omode);
56 static int procimporttsv(const char *path, const char *file, int omode, bool sc);
57 static int procversion(void);
61 int main(int argc, char **argv){
64 const char *ebuf = getenv("TCDBGFD");
65 if(ebuf) g_dbgfd = atoi(ebuf);
68 if(!strcmp(argv[1], "create")){
69 rv = runcreate(argc, argv);
70 } else if(!strcmp(argv[1], "inform")){
71 rv = runinform(argc, argv);
72 } else if(!strcmp(argv[1], "put")){
73 rv = runput(argc, argv);
74 } else if(!strcmp(argv[1], "out")){
75 rv = runout(argc, argv);
76 } else if(!strcmp(argv[1], "get")){
77 rv = runget(argc, argv);
78 } else if(!strcmp(argv[1], "list")){
79 rv = runlist(argc, argv);
80 } else if(!strcmp(argv[1], "optimize")){
81 rv = runoptimize(argc, argv);
82 } else if(!strcmp(argv[1], "importtsv")){
83 rv = runimporttsv(argc, argv);
84 } else if(!strcmp(argv[1], "version") || !strcmp(argv[1], "--version")){
85 rv = runversion(argc, argv);
93 /* print the usage and exit */
94 static void usage(void){
95 fprintf(stderr, "%s: the command line utility of the B+ tree database API\n", g_progname);
96 fprintf(stderr, "\n");
97 fprintf(stderr, "usage:\n");
98 fprintf(stderr, " %s create [-cd|-ci|-cj] [-tl] [-td|-tb] path"
99 " [lmemb [nmemb [bnum [apow [fpow]]]]]\n", g_progname);
100 fprintf(stderr, " %s inform [-nl|-nb] path\n", g_progname);
101 fprintf(stderr, " %s put [-cd|-ci|-cj] [-nl|-nb] [-sx] [-dk|-dc|-dd|-db] path"
102 " key value\n", g_progname);
103 fprintf(stderr, " %s out [-cd|-ci|-cj] [-nl|-nb] [-sx] path key\n", g_progname);
104 fprintf(stderr, " %s get [-cd|-ci|-cj] [-nl|-nb] [-sx] [-px] [-pz] path key\n", g_progname);
105 fprintf(stderr, " %s list [-cd|-ci|-cj] [-nl|-nb] [-m num] [-bk] [-pv] [-px] [-j str]"
106 " [-rb bkey ekey] [-fm str] path\n", g_progname);
107 fprintf(stderr, " %s optimize [-cd|-ci|-cj] [-tl] [-td|-tb] [-tz] [-nl|-nb] path"
108 " [lmemb [nmemb [bnum [apow [fpow]]]]]\n", g_progname);
109 fprintf(stderr, " %s importtsv [-nl|-nb] [-sc] path [file]\n", g_progname);
110 fprintf(stderr, " %s version\n", g_progname);
111 fprintf(stderr, "\n");
116 /* print error information */
117 static void printerr(TCBDB *bdb){
118 const char *path = tcbdbpath(bdb);
119 int ecode = tcbdbecode(bdb);
120 fprintf(stderr, "%s: %s: %d: %s\n", g_progname, path ? path : "-", ecode, tcbdberrmsg(ecode));
124 /* print record data */
125 static int printdata(const char *ptr, int size, bool px){
129 if(len > 0) putchar(' ');
130 len += printf("%02X", *(unsigned char *)ptr);
141 /* create a binary object from a hexadecimal string */
142 static char *hextoobj(const char *str, int *sp){
143 int len = strlen(str);
144 char *buf = tcmalloc(len + 1);
146 for(int i = 0; i < len; i += 2){
147 while(strchr(" \n\r\t\f\v", str[i])){
151 if((mbuf[0] = str[i]) == '\0') break;
152 if((mbuf[1] = str[i+1]) == '\0') break;
154 buf[j++] = (char)strtol(mbuf, NULL, 16);
162 /* read a line from a file descriptor */
163 static char *mygetline(FILE *ifp){
169 while((c = fgetc(ifp)) != EOF){
170 if(blen <= len) blen *= 2;
171 buf = tcrealloc(buf, blen + 1);
172 if(c == '\n' || c == '\r') c = '\0';
176 if(!buf) return NULL;
182 /* dummy comparison function */
183 static int mycmpfunc(const char *aptr, int asiz, const char *bptr, int bsiz, void *op){
188 /* parse arguments of create command */
189 static int runcreate(int argc, char **argv){
198 for(int i = 2; i < argc; i++){
199 if(!path && argv[i][0] == '-'){
200 if(!strcmp(argv[i], "-cd")){
201 cmp = tcbdbcmpdecimal;
202 } else if(!strcmp(argv[i], "-ci")){
204 } else if(!strcmp(argv[i], "-cj")){
206 } else if(!strcmp(argv[i], "-tl")){
208 } else if(!strcmp(argv[i], "-td")){
210 } else if(!strcmp(argv[i], "-tb")){
232 int lmemb = lmstr ? atoi(lmstr) : -1;
233 int nmemb = nmstr ? atoi(nmstr) : -1;
234 int bnum = bstr ? atoi(bstr) : -1;
235 int apow = astr ? atoi(astr) : -1;
236 int fpow = fstr ? atoi(fstr) : -1;
237 int rv = proccreate(path, lmemb, nmemb, bnum, apow, fpow, cmp, opts);
242 /* parse arguments of inform command */
243 static int runinform(int argc, char **argv){
246 for(int i = 2; i < argc; i++){
247 if(!path && argv[i][0] == '-'){
248 if(!strcmp(argv[i], "-nl")){
250 } else if(!strcmp(argv[i], "-nb")){
262 int rv = procinform(path, omode);
267 /* parse arguments of put command */
268 static int runput(int argc, char **argv){
276 for(int i = 2; i < argc; i++){
277 if(!path && argv[i][0] == '-'){
278 if(!strcmp(argv[i], "-cd")){
279 cmp = tcbdbcmpdecimal;
280 } else if(!strcmp(argv[i], "-ci")){
282 } else if(!strcmp(argv[i], "-cj")){
284 } else if(!strcmp(argv[i], "-nl")){
286 } else if(!strcmp(argv[i], "-nb")){
288 } else if(!strcmp(argv[i], "-dk")){
290 } else if(!strcmp(argv[i], "-dc")){
292 } else if(!strcmp(argv[i], "-dd")){
294 } else if(!strcmp(argv[i], "-db")){
296 } else if(!strcmp(argv[i], "-sx")){
311 if(!path || !key || !value) usage();
315 kbuf = hextoobj(key, &ksiz);
316 vbuf = hextoobj(value, &vsiz);
319 kbuf = tcmemdup(key, ksiz);
320 vsiz = strlen(value);
321 vbuf = tcmemdup(value, vsiz);
323 int rv = procput(path, kbuf, ksiz, vbuf, vsiz, cmp, omode, dmode);
330 /* parse arguments of out command */
331 static int runout(int argc, char **argv){
337 for(int i = 2; i < argc; i++){
338 if(!path && argv[i][0] == '-'){
339 if(!strcmp(argv[i], "-cd")){
340 cmp = tcbdbcmpdecimal;
341 } else if(!strcmp(argv[i], "-ci")){
343 } else if(!strcmp(argv[i], "-cj")){
345 } else if(!strcmp(argv[i], "-nl")){
347 } else if(!strcmp(argv[i], "-nb")){
349 } else if(!strcmp(argv[i], "-sx")){
362 if(!path || !key) usage();
366 kbuf = hextoobj(key, &ksiz);
369 kbuf = tcmemdup(key, ksiz);
371 int rv = procout(path, kbuf, ksiz, cmp, omode);
377 /* parse arguments of get command */
378 static int runget(int argc, char **argv){
386 for(int i = 2; i < argc; i++){
387 if(!path && argv[i][0] == '-'){
388 if(!strcmp(argv[i], "-cd")){
389 cmp = tcbdbcmpdecimal;
390 } else if(!strcmp(argv[i], "-ci")){
392 } else if(!strcmp(argv[i], "-cj")){
394 } else if(!strcmp(argv[i], "-nl")){
396 } else if(!strcmp(argv[i], "-nb")){
398 } else if(!strcmp(argv[i], "-sx")){
400 } else if(!strcmp(argv[i], "-px")){
402 } else if(!strcmp(argv[i], "-pz")){
415 if(!path || !key) usage();
419 kbuf = hextoobj(key, &ksiz);
422 kbuf = tcmemdup(key, ksiz);
424 int rv = procget(path, kbuf, ksiz, cmp, omode, px, pz);
430 /* parse arguments of list command */
431 static int runlist(int argc, char **argv){
443 for(int i = 2; i < argc; i++){
444 if(!path && argv[i][0] == '-'){
445 if(!strcmp(argv[i], "-cd")){
446 cmp = tcbdbcmpdecimal;
447 } else if(!strcmp(argv[i], "-ci")){
449 } else if(!strcmp(argv[i], "-cj")){
451 } else if(!strcmp(argv[i], "-nl")){
453 } else if(!strcmp(argv[i], "-nb")){
455 } else if(!strcmp(argv[i], "-m")){
456 if(++i >= argc) usage();
458 } else if(!strcmp(argv[i], "-bk")){
460 } else if(!strcmp(argv[i], "-pv")){
462 } else if(!strcmp(argv[i], "-px")){
464 } else if(!strcmp(argv[i], "-j")){
465 if(++i >= argc) usage();
467 } else if(!strcmp(argv[i], "-rb")){
468 if(++i >= argc) usage();
470 if(++i >= argc) usage();
472 } else if(!strcmp(argv[i], "-fm")){
473 if(++i >= argc) usage();
485 int rv = proclist(path, cmp, omode, max, pv, px, bk, jstr, bstr, estr, fmstr);
490 /* parse arguments of optimize command */
491 static int runoptimize(int argc, char **argv){
499 int opts = UINT8_MAX;
501 for(int i = 2; i < argc; i++){
502 if(!path && argv[i][0] == '-'){
503 if(!strcmp(argv[i], "-cd")){
504 cmp = tcbdbcmpdecimal;
505 } else if(!strcmp(argv[i], "-ci")){
507 } else if(!strcmp(argv[i], "-cj")){
509 } else if(!strcmp(argv[i], "-tl")){
510 if(opts == UINT8_MAX) opts = 0;
512 } else if(!strcmp(argv[i], "-td")){
513 if(opts == UINT8_MAX) opts = 0;
515 } else if(!strcmp(argv[i], "-tb")){
516 if(opts == UINT8_MAX) opts = 0;
518 } else if(!strcmp(argv[i], "-tz")){
519 if(opts == UINT8_MAX) opts = 0;
520 } else if(!strcmp(argv[i], "-nl")){
522 } else if(!strcmp(argv[i], "-nb")){
544 int lmemb = lmstr ? atoi(lmstr) : -1;
545 int nmemb = nmstr ? atoi(nmstr) : -1;
546 int bnum = bstr ? atoi(bstr) : -1;
547 int apow = astr ? atoi(astr) : -1;
548 int fpow = fstr ? atoi(fstr) : -1;
549 int rv = procoptimize(path, lmemb, nmemb, bnum, apow, fpow, cmp, opts, omode);
554 /* parse arguments of importtsv command */
555 static int runimporttsv(int argc, char **argv){
560 for(int i = 2; i < argc; i++){
561 if(!path && argv[i][0] == '-'){
562 if(!strcmp(argv[i], "-nl")){
564 } else if(!strcmp(argv[i], "-nb")){
566 } else if(!strcmp(argv[i], "-sc")){
580 int rv = procimporttsv(path, file, omode, sc);
585 /* parse arguments of version command */
586 static int runversion(int argc, char **argv){
587 int rv = procversion();
592 /* perform create command */
593 static int proccreate(const char *path, int lmemb, int nmemb,
594 int bnum, int apow, int fpow, BDBCMP cmp, int opts){
595 TCBDB *bdb = tcbdbnew();
596 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
597 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
598 if(!tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts)){
603 if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC)){
609 if(!tcbdbclose(bdb)){
618 /* perform inform command */
619 static int procinform(const char *path, int omode){
620 TCBDB *bdb = tcbdbnew();
621 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
622 tcbdbsetcmpfunc(bdb, mycmpfunc, NULL);
623 if(!tcbdbopen(bdb, path, BDBOREADER | omode)){
629 const char *npath = tcbdbpath(bdb);
630 if(!npath) npath = "(unknown)";
631 printf("path: %s\n", npath);
632 printf("database type: btree\n");
633 uint8_t flags = tcbdbflags(bdb);
634 printf("additional flags:");
635 if(flags & BDBFOPEN) printf(" open");
636 if(flags & BDBFFATAL) printf(" fatal");
638 BDBCMP cmp = tcbdbcmpfunc(bdb);
639 printf("comparison function: ");
640 if(cmp == tcbdbcmplexical){
642 } else if(cmp == tcbdbcmpdecimal){
644 } else if(cmp == tcbdbcmpint32){
646 } else if(cmp == tcbdbcmpint64){
652 printf("max leaf member: %d\n", tcbdblmemb(bdb));
653 printf("max node member: %d\n", tcbdbnmemb(bdb));
654 printf("leaf number: %llu\n", (unsigned long long)tcbdblnum(bdb));
655 printf("node number: %llu\n", (unsigned long long)tcbdbnnum(bdb));
656 printf("bucket number: %llu\n", (unsigned long long)tcbdbbnum(bdb));
657 if(bdb->hdb->cnt_writerec >= 0)
658 printf("used bucket number: %lld\n", (long long)tcbdbbnumused(bdb));
659 printf("alignment: %u\n", tcbdbalign(bdb));
660 printf("free block pool: %u\n", tcbdbfbpmax(bdb));
661 printf("inode number: %lld\n", (long long)tcbdbinode(bdb));
663 tcdatestrwww(tcbdbmtime(bdb), INT_MAX, date);
664 printf("modified time: %s\n", date);
665 uint8_t opts = tcbdbopts(bdb);
667 if(opts & BDBTLARGE) printf(" large");
668 if(opts & BDBTDEFLATE) printf(" deflate");
669 if(opts & BDBTTCBS) printf(" tcbs");
671 printf("record number: %llu\n", (unsigned long long)tcbdbrnum(bdb));
672 printf("file size: %llu\n", (unsigned long long)tcbdbfsiz(bdb));
673 if(!tcbdbclose(bdb)){
674 if(!err) printerr(bdb);
682 /* perform put command */
683 static int procput(const char *path, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
684 BDBCMP cmp, int omode, int dmode){
685 TCBDB *bdb = tcbdbnew();
686 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
687 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
688 if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
696 if(!tcbdbputkeep(bdb, kbuf, ksiz, vbuf, vsiz)){
702 if(!tcbdbputcat(bdb, kbuf, ksiz, vbuf, vsiz)){
708 if(!tcbdbputdup(bdb, kbuf, ksiz, vbuf, vsiz)){
714 if(!tcbdbputdupback(bdb, kbuf, ksiz, vbuf, vsiz)){
720 if(!tcbdbput(bdb, kbuf, ksiz, vbuf, vsiz)){
726 if(!tcbdbclose(bdb)){
727 if(!err) printerr(bdb);
735 /* perform out command */
736 static int procout(const char *path, const char *kbuf, int ksiz, BDBCMP cmp, int omode){
737 TCBDB *bdb = tcbdbnew();
738 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
739 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
740 if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
746 if(!tcbdbout(bdb, kbuf, ksiz)){
750 if(!tcbdbclose(bdb)){
751 if(!err) printerr(bdb);
759 /* perform get command */
760 static int procget(const char *path, const char *kbuf, int ksiz, BDBCMP cmp, int omode,
762 TCBDB *bdb = tcbdbnew();
763 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
764 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
765 if(!tcbdbopen(bdb, path, BDBOREADER | omode)){
772 char *vbuf = tcbdbget(bdb, kbuf, ksiz, &vsiz);
774 printdata(vbuf, vsiz, px);
775 if(!pz) putchar('\n');
781 if(!tcbdbclose(bdb)){
782 if(!err) printerr(bdb);
790 /* perform list command */
791 static int proclist(const char *path, BDBCMP cmp, int omode, int max, bool pv, bool px, bool bk,
792 const char *jstr, const char *bstr, const char *estr, const char *fmstr){
793 TCBDB *bdb = tcbdbnew();
794 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
795 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
796 if(!tcbdbopen(bdb, path, BDBOREADER | omode)){
803 TCLIST *keys = fmstr ? tcbdbfwmkeys2(bdb, fmstr, max) :
804 tcbdbrange(bdb, bstr, strlen(bstr), true, estr, strlen(estr), true, max);
806 for(int i = 0; i < tclistnum(keys); i++){
808 const char *kbuf = tclistval(keys, i, &ksiz);
810 TCLIST *vals = tcbdbget4(bdb, kbuf, ksiz);
812 for(int j = 0; j < tclistnum(vals); j++){
814 const char *vbuf = tclistval(vals, j, &vsiz);
815 printdata(kbuf, ksiz, px);
817 printdata(vbuf, vsiz, px);
819 if(max >= 0 && ++cnt >= max) break;
824 int num = tcbdbvnum(bdb, kbuf, ksiz);
825 for(int j = 0; j < num; j++){
826 printdata(kbuf, ksiz, px);
828 if(max >= 0 && ++cnt >= max) break;
831 if(max >= 0 && cnt >= max) break;
835 BDBCUR *cur = tcbdbcurnew(bdb);
838 if(!tcbdbcurjumpback(cur, jstr, strlen(jstr)) && tcbdbecode(bdb) != TCENOREC){
843 if(!tcbdbcurlast(cur) && tcbdbecode(bdb) != TCENOREC){
850 if(!tcbdbcurjump(cur, jstr, strlen(jstr)) && tcbdbecode(bdb) != TCENOREC){
855 if(!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC){
861 TCXSTR *key = tcxstrnew();
862 TCXSTR *val = tcxstrnew();
864 while(tcbdbcurrec(cur, key, val)){
865 printdata(tcxstrptr(key), tcxstrsize(key), px);
868 printdata(tcxstrptr(val), tcxstrsize(val), px);
872 if(!tcbdbcurprev(cur) && tcbdbecode(bdb) != TCENOREC){
877 if(!tcbdbcurnext(cur) && tcbdbecode(bdb) != TCENOREC){
882 if(max >= 0 && ++cnt >= max) break;
888 if(!tcbdbclose(bdb)){
889 if(!err) printerr(bdb);
897 /* perform optimize command */
898 static int procoptimize(const char *path, int lmemb, int nmemb,
899 int bnum, int apow, int fpow, BDBCMP cmp, int opts, int omode){
900 TCBDB *bdb = tcbdbnew();
901 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
902 if(cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb);
903 if(!tcbdbopen(bdb, path, BDBOWRITER | omode)){
909 if(!tcbdboptimize(bdb, lmemb, nmemb, bnum, apow, fpow, opts)){
913 if(!tcbdbclose(bdb)){
914 if(!err) printerr(bdb);
922 /* perform importtsv command */
923 static int procimporttsv(const char *path, const char *file, int omode, bool sc){
924 TCBDB *bdb = tcbdbnew();
925 if(g_dbgfd >= 0) tcbdbsetdbgfd(bdb, g_dbgfd);
926 FILE *ifp = file ? fopen(file, "rb") : stdin;
928 fprintf(stderr, "%s: could not open\n", file ? file : "(stdin)");
932 if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | omode)){
940 while(!err && (line = mygetline(ifp)) != NULL){
941 char *pv = strchr(line, '\t');
944 if(sc) tcstrtolower(line);
945 if(!tcbdbputdup2(bdb, line, pv + 1) && tcbdbecode(bdb) != TCEKEEP){
950 if(cnt > 0 && cnt % 100 == 0){
953 if(cnt % 5000 == 0) printf(" (%08d)\n", cnt);
957 printf(" (%08d)\n", cnt);
958 if(!tcbdbclose(bdb)){
959 if(!err) printerr(bdb);
963 if(ifp != stdin) fclose(ifp);
968 /* perform version command */
969 static int procversion(void){
970 printf("Tokyo Cabinet version %s (%d:%s)\n", tcversion, _TC_LIBVER, _TC_FORMATVER);
971 printf("Copyright (C) 2006-2008 Mikio Hirabayashi\n");