1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_stat.c,v 12.23 2008/01/08 20:58:16 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13#ifndef lint 14static const char copyright[] = 15 "Copyright (c) 1996,2008 Oracle. All rights reserved.\n"; 16#endif 17 18typedef enum { T_NOTSET, T_DB, 19 T_ENV, T_LOCK, T_LOG, T_MPOOL, T_MUTEX, T_REP, T_TXN } test_t; 20 21int db_init __P((DB_ENV *, char *, test_t, u_int32_t, int *)); 22int main __P((int, char *[])); 23int usage __P((void)); 24int version_check __P((void)); 25 26const char *progname; 27 28int 29main(argc, argv) 30 int argc; 31 char *argv[]; 32{ 33 extern char *optarg; 34 extern int optind; 35 DB_ENV *dbenv; 36 DB *dbp; 37 test_t ttype; 38 u_int32_t cache, flags; 39 int ch, exitval; 40 int nflag, private, resize, ret; 41 char *db, *home, *p, *passwd, *subdb; 42 43 if ((progname = __db_rpath(argv[0])) == NULL) 44 progname = argv[0]; 45 else 46 ++progname; 47 48 if ((ret = version_check()) != 0) 49 return (ret); 50 51 dbenv = NULL; 52 dbp = NULL; 53 ttype = T_NOTSET; 54 cache = MEGABYTE; 55 exitval = flags = nflag = private = 0; 56 db = home = passwd = subdb = NULL; 57 58 while ((ch = getopt(argc, 59 argv, "C:cd:Eefgh:L:lM:mNP:R:rs:tVxX:Z")) != EOF) 60 switch (ch) { 61 case 'C': case 'c': 62 if (ttype != T_NOTSET && ttype != T_LOCK) 63 goto argcombo; 64 ttype = T_LOCK; 65 if (ch != 'c') 66 for (p = optarg; *p; ++p) 67 switch (*p) { 68 case 'A': 69 LF_SET(DB_STAT_ALL); 70 break; 71 case 'c': 72 LF_SET(DB_STAT_LOCK_CONF); 73 break; 74 case 'l': 75 LF_SET(DB_STAT_LOCK_LOCKERS); 76 break; 77 case 'm': /* Backward compatible. */ 78 break; 79 case 'o': 80 LF_SET(DB_STAT_LOCK_OBJECTS); 81 break; 82 case 'p': 83 LF_SET(DB_STAT_LOCK_PARAMS); 84 break; 85 default: 86 return (usage()); 87 } 88 break; 89 case 'd': 90 if (ttype != T_NOTSET && ttype != T_DB) 91 goto argcombo; 92 ttype = T_DB; 93 db = optarg; 94 break; 95 case 'E': case 'e': 96 if (ttype != T_NOTSET && ttype != T_ENV) 97 goto argcombo; 98 ttype = T_ENV; 99 LF_SET(DB_STAT_SUBSYSTEM); 100 if (ch == 'E') 101 LF_SET(DB_STAT_ALL); 102 break; 103 case 'f': 104 if (ttype != T_NOTSET && ttype != T_DB) 105 goto argcombo; 106 ttype = T_DB; 107 LF_SET(DB_FAST_STAT); 108 break; 109 case 'h': 110 home = optarg; 111 break; 112 case 'L': case 'l': 113 if (ttype != T_NOTSET && ttype != T_LOG) 114 goto argcombo; 115 ttype = T_LOG; 116 if (ch != 'l') 117 for (p = optarg; *p; ++p) 118 switch (*p) { 119 case 'A': 120 LF_SET(DB_STAT_ALL); 121 break; 122 default: 123 return (usage()); 124 } 125 break; 126 case 'M': case 'm': 127 if (ttype != T_NOTSET && ttype != T_MPOOL) 128 goto argcombo; 129 ttype = T_MPOOL; 130 if (ch != 'm') 131 for (p = optarg; *p; ++p) 132 switch (*p) { 133 case 'A': 134 LF_SET(DB_STAT_ALL); 135 break; 136 case 'h': 137 LF_SET(DB_STAT_MEMP_HASH); 138 break; 139 case 'm': /* Backward compatible. */ 140 break; 141 default: 142 return (usage()); 143 } 144 break; 145 case 'N': 146 nflag = 1; 147 break; 148 case 'P': 149 passwd = strdup(optarg); 150 memset(optarg, 0, strlen(optarg)); 151 if (passwd == NULL) { 152 fprintf(stderr, "%s: strdup: %s\n", 153 progname, strerror(errno)); 154 return (EXIT_FAILURE); 155 } 156 break; 157 case 'R': case 'r': 158 if (ttype != T_NOTSET && ttype != T_REP) 159 goto argcombo; 160 ttype = T_REP; 161 if (ch != 'r') 162 for (p = optarg; *p; ++p) 163 switch (*p) { 164 case 'A': 165 LF_SET(DB_STAT_ALL); 166 break; 167 default: 168 return (usage()); 169 } 170 break; 171 case 's': 172 if (ttype != T_NOTSET && ttype != T_DB) 173 goto argcombo; 174 ttype = T_DB; 175 subdb = optarg; 176 break; 177 case 't': 178 if (ttype != T_NOTSET) { 179argcombo: fprintf(stderr, 180 "%s: illegal option combination\n", 181 progname); 182 return (usage()); 183 } 184 ttype = T_TXN; 185 break; 186 case 'V': 187 printf("%s\n", db_version(NULL, NULL, NULL)); 188 return (EXIT_SUCCESS); 189 case 'X': case 'x': 190 if (ttype != T_NOTSET && ttype != T_MUTEX) 191 goto argcombo; 192 ttype = T_MUTEX; 193 if (ch != 'x') 194 for (p = optarg; *p; ++p) 195 switch (*p) { 196 case 'A': 197 LF_SET(DB_STAT_ALL); 198 break; 199 default: 200 return (usage()); 201 } 202 break; 203 case 'Z': 204 LF_SET(DB_STAT_CLEAR); 205 break; 206 case '?': 207 default: 208 return (usage()); 209 } 210 argc -= optind; 211 argv += optind; 212 213 switch (ttype) { 214 case T_DB: 215 if (db == NULL) 216 return (usage()); 217 break; 218 case T_ENV: 219 case T_LOCK: 220 case T_LOG: 221 case T_MPOOL: 222 case T_MUTEX: 223 case T_REP: 224 case T_TXN: 225 break; 226 case T_NOTSET: 227 return (usage()); 228 } 229 230 /* Handle possible interruptions. */ 231 __db_util_siginit(); 232 233 /* 234 * Create an environment object and initialize it for error 235 * reporting. 236 */ 237retry: if ((ret = db_env_create(&dbenv, 0)) != 0) { 238 fprintf(stderr, 239 "%s: db_env_create: %s\n", progname, db_strerror(ret)); 240 goto err; 241 } 242 243 dbenv->set_errfile(dbenv, stderr); 244 dbenv->set_errpfx(dbenv, progname); 245 246 if (nflag) { 247 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) { 248 dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING"); 249 goto err; 250 } 251 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) { 252 dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC"); 253 goto err; 254 } 255 } 256 257 if (passwd != NULL && 258 (ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES)) != 0) { 259 dbenv->err(dbenv, ret, "set_passwd"); 260 goto err; 261 } 262 263 /* Initialize the environment. */ 264 if (db_init(dbenv, home, ttype, cache, &private) != 0) 265 goto err; 266 267 switch (ttype) { 268 case T_DB: 269 /* Create the DB object and open the file. */ 270 if ((ret = db_create(&dbp, dbenv, 0)) != 0) { 271 dbenv->err(dbenv, ret, "db_create"); 272 goto err; 273 } 274 275 /* 276 * We open the database for writing so we can update the cached 277 * statistics, but it's OK to fail, we can open read-only and 278 * proceed. 279 * 280 * Turn off error messages for now -- we can't open lots of 281 * databases read-write (for example, master databases and 282 * hash databases for which we don't know the hash function). 283 */ 284 dbenv->set_errfile(dbenv, NULL); 285 ret = dbp->open(dbp, NULL, db, subdb, DB_UNKNOWN, 0, 0); 286 dbenv->set_errfile(dbenv, stderr); 287 if (ret != 0 && (ret = dbp->open( 288 dbp, NULL, db, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0) { 289 dbenv->err(dbenv, ret, "DB->open: %s", db); 290 goto err; 291 } 292 293 /* Check if cache is too small for this DB's pagesize. */ 294 if (private) { 295 if ((ret = __db_util_cache(dbp, &cache, &resize)) != 0) 296 goto err; 297 if (resize) { 298 (void)dbp->close(dbp, DB_NOSYNC); 299 dbp = NULL; 300 301 (void)dbenv->close(dbenv, 0); 302 dbenv = NULL; 303 goto retry; 304 } 305 } 306 307 if (dbp->stat_print(dbp, flags)) 308 goto err; 309 break; 310 case T_ENV: 311 if (dbenv->stat_print(dbenv, flags)) 312 goto err; 313 break; 314 case T_LOCK: 315 if (dbenv->lock_stat_print(dbenv, flags)) 316 goto err; 317 break; 318 case T_LOG: 319 if (dbenv->log_stat_print(dbenv, flags)) 320 goto err; 321 break; 322 case T_MPOOL: 323 if (dbenv->memp_stat_print(dbenv, flags)) 324 goto err; 325 break; 326 case T_MUTEX: 327 if (dbenv->mutex_stat_print(dbenv, flags)) 328 goto err; 329 break; 330 case T_REP: 331#ifdef HAVE_REPLICATION_THREADS 332 if (dbenv->repmgr_stat_print(dbenv, flags)) 333 goto err; 334#endif 335 if (dbenv->rep_stat_print(dbenv, flags)) 336 goto err; 337 break; 338 case T_TXN: 339 if (dbenv->txn_stat_print(dbenv, flags)) 340 goto err; 341 break; 342 case T_NOTSET: 343 dbenv->errx(dbenv, "Unknown statistics flag"); 344 goto err; 345 } 346 347 if (0) { 348err: exitval = 1; 349 } 350 if (dbp != NULL && (ret = dbp->close(dbp, DB_NOSYNC)) != 0) { 351 exitval = 1; 352 dbenv->err(dbenv, ret, "close"); 353 } 354 if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) { 355 exitval = 1; 356 fprintf(stderr, 357 "%s: dbenv->close: %s\n", progname, db_strerror(ret)); 358 } 359 360 if (passwd != NULL) 361 free(passwd); 362 363 /* Resend any caught signal. */ 364 __db_util_sigresend(); 365 366 return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 367} 368 369/* 370 * db_init -- 371 * Initialize the environment. 372 */ 373int 374db_init(dbenv, home, ttype, cache, is_private) 375 DB_ENV *dbenv; 376 char *home; 377 test_t ttype; 378 u_int32_t cache; 379 int *is_private; 380{ 381 u_int32_t oflags; 382 int ret; 383 384 /* 385 * If our environment open fails, and we're trying to look at a 386 * shared region, it's a hard failure. 387 * 388 * We will probably just drop core if the environment we join does 389 * not include a memory pool. This is probably acceptable; trying 390 * to use an existing environment that does not contain a memory 391 * pool to look at a database can be safely construed as operator 392 * error, I think. 393 */ 394 *is_private = 0; 395 if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) == 0) 396 return (0); 397 if (ret == DB_VERSION_MISMATCH) 398 goto err; 399 if (ttype != T_DB && ttype != T_LOG) { 400 dbenv->err(dbenv, ret, "DB_ENV->open%s%s", 401 home == NULL ? "" : ": ", home == NULL ? "" : home); 402 return (1); 403 } 404 405 /* 406 * We're looking at a database or set of log files and no environment 407 * exists. Create one, but make it private so no files are actually 408 * created. Declare a reasonably large cache so that we don't fail 409 * when reporting statistics on large databases. 410 * 411 * An environment is required to look at databases because we may be 412 * trying to look at databases in directories other than the current 413 * one. 414 */ 415 if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) { 416 dbenv->err(dbenv, ret, "set_cachesize"); 417 return (1); 418 } 419 *is_private = 1; 420 oflags = DB_CREATE | DB_PRIVATE | DB_USE_ENVIRON; 421 if (ttype == T_DB) 422 oflags |= DB_INIT_MPOOL; 423 if (ttype == T_LOG) 424 oflags |= DB_INIT_LOG; 425 if ((ret = dbenv->open(dbenv, home, oflags, 0)) == 0) 426 return (0); 427 428 /* An environment is required. */ 429err: dbenv->err(dbenv, ret, "DB_ENV->open"); 430 return (1); 431} 432 433int 434usage() 435{ 436 fprintf(stderr, "usage: %s %s\n", progname, 437 "-d file [-fN] [-h home] [-P password] [-s database]"); 438 fprintf(stderr, "usage: %s %s\n\t%s\n", progname, 439 "[-cEelmNrtVxZ] [-C Aclop]", 440 "[-h home] [-L A] [-M A] [-P password] [-R A] [-X A]"); 441 return (EXIT_FAILURE); 442} 443 444int 445version_check() 446{ 447 int v_major, v_minor, v_patch; 448 449 /* Make sure we're loaded with the right version of the DB library. */ 450 (void)db_version(&v_major, &v_minor, &v_patch); 451 if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) { 452 fprintf(stderr, 453 "%s: version %d.%d doesn't match library version %d.%d\n", 454 progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, 455 v_major, v_minor); 456 return (EXIT_FAILURE); 457 } 458 return (0); 459} 460