1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "couchstore_config.h"
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <inttypes.h>
7 #include <libcouchstore/couch_db.h>
8 #include <snappy-c.h>
9 #include <getopt.h>
10 
11 #include "internal.h"
12 #include "util.h"
13 #include "bitfield.h"
14 
15 
size_str(double size)16 static char *size_str(double size)
17 {
18     static char rfs[256];
19     int i = 0;
20     const char *units[] = {"bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
21     while (size > 1024) {
22         size /= 1024;
23         i++;
24     }
25     snprintf(rfs, sizeof(rfs), "%.*f %s", i, size, units[i]);
26     return rfs;
27 }
28 
print_db_info(Db* db)29 static void print_db_info(Db* db)
30 {
31     DbInfo info;
32     couchstore_db_info(db, &info);
33     printf("   doc count: %" PRIu64 "\n", info.doc_count);
34     printf("   deleted doc count: %" PRIu64 "\n", info.deleted_count);
35     printf("   data size: %s\n", size_str(info.space_used));
36 }
37 
process_file(const char *file, int iterate_headers)38 static int process_file(const char *file, int iterate_headers)
39 {
40     Db *db;
41     couchstore_error_t errcode;
42     uint64_t btreesize = 0;
43     const char* crc_strings[3] = {"warning crc is set to unknown",
44                                   "CRC-32",
45                                   "CRC-32C"};
46 
47     errcode = couchstore_open_db(file, COUCHSTORE_OPEN_FLAG_RDONLY, &db);
48     if (errcode != COUCHSTORE_SUCCESS) {
49         fprintf(stderr, "Failed to open \"%s\": %s\n",
50                 file, couchstore_strerror(errcode));
51         return -1;
52     }
53 
54 next_header:
55     printf("DB Info (%s) - header at %" PRIu64 "\n", file, db->header.position);
56     printf("   file format version: %" PRIu64 "\n", db->header.disk_version);
57     printf("   update_seq: %" PRIu64 "\n", db->header.update_seq);
58     printf("   purge_seq: %" PRIu64 "\n", db->header.purge_seq);
59 
60     if (db->file.crc_mode < 3) {
61         printf("   crc: %s\n", crc_strings[db->file.crc_mode]);
62     } else {
63         printf("   crc: warning crc_mode is out of range %" PRIu32 "\n",  db->file.crc_mode);
64     }
65 
66     print_db_info(db);
67     if (db->header.by_id_root) {
68         btreesize += db->header.by_id_root->subtreesize;
69     }
70     if (db->header.by_seq_root) {
71         btreesize += db->header.by_seq_root->subtreesize;
72     }
73     printf("   B-tree size: %s\n", size_str(btreesize));
74     printf("   total disk size: %s\n", size_str(db->file.pos));
75     if (iterate_headers) {
76         if (couchstore_rewind_db_header(db) == COUCHSTORE_SUCCESS) {
77             printf("\n");
78             goto next_header;
79         }
80     } else {
81         couchstore_close_file(db);
82         couchstore_free_db(db);
83     }
84 
85     return 0;
86 }
87 
usage(const char *name)88 static void usage(const char *name)
89 {
90     fprintf(stderr, "USAGE: %s [-i] <file.couch>\n", name);
91     fprintf(stderr, "\t-i Iterate through all headers\n");
92     exit(EXIT_FAILURE);
93 }
94 
main(int argc, char **argv)95 int main(int argc, char **argv)
96 {
97     int error = 0;
98     int ii;
99     int iterate_headers = getenv("ITERATE_HEADERS") != NULL;
100     int cmd;
101 
102     while ((cmd = getopt(argc, argv, "i")) != -1) {
103         switch (cmd) {
104         case 'i':
105             iterate_headers = 1;
106             break;
107         default:
108             usage(argv[0]);
109             /* NOTREACHED */
110         }
111     }
112 
113     if (optind == argc) {
114         usage(argv[0]);
115     }
116 
117     for (ii = optind; ii < argc; ++ii) {
118         error += process_file(argv[ii], iterate_headers);
119     }
120 
121     if (error) {
122         exit(EXIT_FAILURE);
123     } else {
124         exit(EXIT_SUCCESS);
125     }
126 }
127