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