mdb_stat.c revision 1.1.1.1.6.2 1 /* $NetBSD: mdb_stat.c,v 1.1.1.1.6.2 2014/08/19 23:52:00 tls Exp $ */
2
3 /* mdb_stat.c - memory-mapped database status tool */
4 /*
5 * Copyright 2011-2013 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include "lmdb.h"
21
22 #ifdef _WIN32
23 #define Z "I"
24 #else
25 #define Z "z"
26 #endif
27
28 static void prstat(MDB_stat *ms)
29 {
30 #if 0
31 printf(" Page size: %u\n", ms->ms_psize);
32 #endif
33 printf(" Tree depth: %u\n", ms->ms_depth);
34 printf(" Branch pages: %"Z"u\n", ms->ms_branch_pages);
35 printf(" Leaf pages: %"Z"u\n", ms->ms_leaf_pages);
36 printf(" Overflow pages: %"Z"u\n", ms->ms_overflow_pages);
37 printf(" Entries: %"Z"u\n", ms->ms_entries);
38 }
39
40 static void usage(char *prog)
41 {
42 fprintf(stderr, "usage: %s dbpath [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb]\n", prog);
43 exit(EXIT_FAILURE);
44 }
45
46 int main(int argc, char *argv[])
47 {
48 int i, rc;
49 MDB_env *env;
50 MDB_txn *txn;
51 MDB_dbi dbi;
52 MDB_stat mst;
53 MDB_envinfo mei;
54 char *prog = argv[0];
55 char *envname;
56 char *subname = NULL;
57 int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0;
58
59 if (argc < 2) {
60 usage(prog);
61 }
62
63 /* -a: print stat of main DB and all subDBs
64 * -s: print stat of only the named subDB
65 * -e: print env info
66 * -f: print freelist info
67 * -r: print reader info
68 * -n: use NOSUBDIR flag on env_open
69 * (default) print stat of only the main DB
70 */
71 while ((i = getopt(argc, argv, "aefnrs:")) != EOF) {
72 switch(i) {
73 case 'a':
74 if (subname)
75 usage(prog);
76 alldbs++;
77 break;
78 case 'e':
79 envinfo++;
80 break;
81 case 'f':
82 freinfo++;
83 break;
84 case 'n':
85 envflags |= MDB_NOSUBDIR;
86 break;
87 case 'r':
88 rdrinfo++;
89 break;
90 case 's':
91 if (alldbs)
92 usage(prog);
93 subname = optarg;
94 break;
95 default:
96 usage(prog);
97 }
98 }
99
100 if (optind != argc - 1)
101 usage(prog);
102
103 envname = argv[optind];
104 rc = mdb_env_create(&env);
105
106 if (alldbs || subname) {
107 mdb_env_set_maxdbs(env, 4);
108 }
109
110 rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
111 if (rc) {
112 printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
113 goto env_close;
114 }
115
116 if (envinfo) {
117 rc = mdb_env_stat(env, &mst);
118 rc = mdb_env_info(env, &mei);
119 printf("Environment Info\n");
120 printf(" Map address: %p\n", mei.me_mapaddr);
121 printf(" Map size: %"Z"u\n", mei.me_mapsize);
122 printf(" Page size: %u\n", mst.ms_psize);
123 printf(" Max pages: %"Z"u\n", mei.me_mapsize / mst.ms_psize);
124 printf(" Number of pages used: %"Z"u\n", mei.me_last_pgno+1);
125 printf(" Last transaction ID: %"Z"u\n", mei.me_last_txnid);
126 printf(" Max readers: %u\n", mei.me_maxreaders);
127 printf(" Number of readers used: %u\n", mei.me_numreaders);
128 }
129
130 if (rdrinfo) {
131 printf("Reader Table Status\n");
132 rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout);
133 if (rdrinfo > 1) {
134 int dead;
135 mdb_reader_check(env, &dead);
136 printf(" %d stale readers cleared.\n", dead);
137 rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout);
138 }
139 if (!(subname || alldbs || freinfo))
140 goto env_close;
141 }
142
143 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
144 if (rc) {
145 printf("mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
146 goto env_close;
147 }
148
149 if (freinfo) {
150 MDB_cursor *cursor;
151 MDB_val key, data;
152 size_t pages = 0, *iptr;
153
154 printf("Freelist Status\n");
155 dbi = 0;
156 rc = mdb_cursor_open(txn, dbi, &cursor);
157 if (rc) {
158 printf("mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
159 goto txn_abort;
160 }
161 rc = mdb_stat(txn, dbi, &mst);
162 if (rc) {
163 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
164 goto txn_abort;
165 }
166 prstat(&mst);
167 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
168 iptr = data.mv_data;
169 pages += *iptr;
170 if (freinfo > 1) {
171 char *bad = "";
172 size_t pg, prev;
173 ssize_t i, j, span = 0;
174 j = *iptr++;
175 for (i = j, prev = 1; --i >= 0; ) {
176 pg = iptr[i];
177 if (pg <= prev)
178 bad = " [bad sequence]";
179 prev = pg;
180 pg += span;
181 for (; i >= span && iptr[i-span] == pg; span++, pg++) ;
182 }
183 printf(" Transaction %"Z"u, %"Z"d pages, maxspan %"Z"d%s\n",
184 *(size_t *)key.mv_data, j, span, bad);
185 if (freinfo > 2) {
186 for (--j; j >= 0; ) {
187 pg = iptr[j];
188 for (span=1; --j >= 0 && iptr[j] == pg+span; span++) ;
189 printf(span>1 ? " %9"Z"u[%"Z"d]\n" : " %9"Z"u\n",
190 pg, span);
191 }
192 }
193 }
194 }
195 mdb_cursor_close(cursor);
196 printf(" Free pages: %"Z"u\n", pages);
197 }
198
199 rc = mdb_open(txn, subname, 0, &dbi);
200 if (rc) {
201 printf("mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
202 goto txn_abort;
203 }
204
205 rc = mdb_stat(txn, dbi, &mst);
206 if (rc) {
207 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
208 goto txn_abort;
209 }
210 printf("Status of %s\n", subname ? subname : "Main DB");
211 prstat(&mst);
212
213 if (alldbs) {
214 MDB_cursor *cursor;
215 MDB_val key;
216
217 rc = mdb_cursor_open(txn, dbi, &cursor);
218 if (rc) {
219 printf("mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
220 goto txn_abort;
221 }
222 while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
223 char *str;
224 MDB_dbi db2;
225 if (memchr(key.mv_data, '\0', key.mv_size))
226 continue;
227 str = malloc(key.mv_size+1);
228 memcpy(str, key.mv_data, key.mv_size);
229 str[key.mv_size] = '\0';
230 rc = mdb_open(txn, str, 0, &db2);
231 if (rc == MDB_SUCCESS)
232 printf("Status of %s\n", str);
233 free(str);
234 if (rc) continue;
235 rc = mdb_stat(txn, db2, &mst);
236 if (rc) {
237 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
238 goto txn_abort;
239 }
240 prstat(&mst);
241 mdb_close(env, db2);
242 }
243 mdb_cursor_close(cursor);
244 }
245
246 if (rc == MDB_NOTFOUND)
247 rc = MDB_SUCCESS;
248
249 mdb_close(env, dbi);
250 txn_abort:
251 mdb_txn_abort(txn);
252 env_close:
253 mdb_env_close(env);
254
255 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
256 }
257