xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblmdb/mdb_stat.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: mdb_stat.c,v 1.1.1.1 2014/05/28 09:58:42 tron 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