1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_stati.c,v 12.37 2008/01/08 20:58:10 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/btree.h" 14#include "dbinc/hash.h" 15#include "dbinc/qam.h" 16#include "dbinc/lock.h" 17#include "dbinc/log.h" 18#include "dbinc/mp.h" 19 20#ifdef HAVE_STATISTICS 21static int __db_print_all __P((DB *, u_int32_t)); 22static int __db_print_citem __P((DBC *)); 23static int __db_print_cursor __P((DB *)); 24static int __db_print_stats __P((DB *, DB_THREAD_INFO *, u_int32_t)); 25static int __db_stat __P((DB *, DB_THREAD_INFO *, DB_TXN *, void *, u_int32_t)); 26static int __db_stat_arg __P((DB *, u_int32_t)); 27 28/* 29 * __db_stat_pp -- 30 * DB->stat pre/post processing. 31 * 32 * PUBLIC: int __db_stat_pp __P((DB *, DB_TXN *, void *, u_int32_t)); 33 */ 34int 35__db_stat_pp(dbp, txn, spp, flags) 36 DB *dbp; 37 DB_TXN *txn; 38 void *spp; 39 u_int32_t flags; 40{ 41 DB_THREAD_INFO *ip; 42 ENV *env; 43 int handle_check, ret, t_ret; 44 45 env = dbp->env; 46 47 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat"); 48 49 if ((ret = __db_stat_arg(dbp, flags)) != 0) 50 return (ret); 51 52 ENV_ENTER(env, ip); 53 54 /* Check for replication block. */ 55 handle_check = IS_ENV_REPLICATED(env); 56 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) { 57 handle_check = 0; 58 goto err; 59 } 60 61 ret = __db_stat(dbp, ip, txn, spp, flags); 62 63 /* Release replication block. */ 64 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 65 ret = t_ret; 66 67err: ENV_LEAVE(env, ip); 68 return (ret); 69} 70 71/* 72 * __db_stat -- 73 * DB->stat. 74 * 75 */ 76static int 77__db_stat(dbp, ip, txn, spp, flags) 78 DB *dbp; 79 DB_THREAD_INFO *ip; 80 DB_TXN *txn; 81 void *spp; 82 u_int32_t flags; 83{ 84 DBC *dbc; 85 ENV *env; 86 int ret, t_ret; 87 88 env = dbp->env; 89 90 /* Acquire a cursor. */ 91 if ((ret = __db_cursor(dbp, ip, txn, 92 &dbc, LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED))) != 0) 93 return (ret); 94 95 DEBUG_LWRITE(dbc, NULL, "DB->stat", NULL, NULL, flags); 96 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED); 97 98 switch (dbp->type) { 99 case DB_BTREE: 100 case DB_RECNO: 101 ret = __bam_stat(dbc, spp, flags); 102 break; 103 case DB_HASH: 104 ret = __ham_stat(dbc, spp, flags); 105 break; 106 case DB_QUEUE: 107 ret = __qam_stat(dbc, spp, flags); 108 break; 109 case DB_UNKNOWN: 110 default: 111 ret = (__db_unknown_type(env, "DB->stat", dbp->type)); 112 break; 113 } 114 115 if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0) 116 ret = t_ret; 117 118 return (ret); 119} 120 121/* 122 * __db_stat_arg -- 123 * Check DB->stat arguments. 124 */ 125static int 126__db_stat_arg(dbp, flags) 127 DB *dbp; 128 u_int32_t flags; 129{ 130 ENV *env; 131 132 env = dbp->env; 133 134 /* Check for invalid function flags. */ 135 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED); 136 switch (flags) { 137 case 0: 138 case DB_FAST_STAT: 139 break; 140 default: 141 return (__db_ferr(env, "DB->stat", 0)); 142 } 143 144 return (0); 145} 146 147/* 148 * __db_stat_print_pp -- 149 * DB->stat_print pre/post processing. 150 * 151 * PUBLIC: int __db_stat_print_pp __P((DB *, u_int32_t)); 152 */ 153int 154__db_stat_print_pp(dbp, flags) 155 DB *dbp; 156 u_int32_t flags; 157{ 158 DB_THREAD_INFO *ip; 159 ENV *env; 160 int handle_check, ret, t_ret; 161 162 env = dbp->env; 163 164 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat_print"); 165 166 /* 167 * !!! 168 * The actual argument checking is simple, do it inline. 169 */ 170 if ((ret = __db_fchk(env, 171 "DB->stat_print", flags, DB_FAST_STAT | DB_STAT_ALL)) != 0) 172 return (ret); 173 174 ENV_ENTER(env, ip); 175 176 /* Check for replication block. */ 177 handle_check = IS_ENV_REPLICATED(env); 178 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) { 179 handle_check = 0; 180 goto err; 181 } 182 183 ret = __db_stat_print(dbp, ip, flags); 184 185 /* Release replication block. */ 186 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 187 ret = t_ret; 188 189err: ENV_LEAVE(env, ip); 190 return (ret); 191} 192 193/* 194 * __db_stat_print -- 195 * DB->stat_print. 196 * 197 * PUBLIC: int __db_stat_print __P((DB *, DB_THREAD_INFO *, u_int32_t)); 198 */ 199int 200__db_stat_print(dbp, ip, flags) 201 DB *dbp; 202 DB_THREAD_INFO *ip; 203 u_int32_t flags; 204{ 205 time_t now; 206 int ret; 207 char time_buf[CTIME_BUFLEN]; 208 209 (void)time(&now); 210 __db_msg(dbp->env, "%.24s\tLocal time", __os_ctime(&now, time_buf)); 211 212 if (LF_ISSET(DB_STAT_ALL) && (ret = __db_print_all(dbp, flags)) != 0) 213 return (ret); 214 215 if ((ret = __db_print_stats(dbp, ip, flags)) != 0) 216 return (ret); 217 218 return (0); 219} 220 221/* 222 * __db_print_stats -- 223 * Display default DB handle statistics. 224 */ 225static int 226__db_print_stats(dbp, ip, flags) 227 DB *dbp; 228 DB_THREAD_INFO *ip; 229 u_int32_t flags; 230{ 231 DBC *dbc; 232 ENV *env; 233 int ret, t_ret; 234 235 env = dbp->env; 236 237 /* Acquire a cursor. */ 238 if ((ret = __db_cursor(dbp, ip, NULL, &dbc, 0)) != 0) 239 return (ret); 240 241 DEBUG_LWRITE(dbc, NULL, "DB->stat_print", NULL, NULL, 0); 242 243 switch (dbp->type) { 244 case DB_BTREE: 245 case DB_RECNO: 246 ret = __bam_stat_print(dbc, flags); 247 break; 248 case DB_HASH: 249 ret = __ham_stat_print(dbc, flags); 250 break; 251 case DB_QUEUE: 252 ret = __qam_stat_print(dbc, flags); 253 break; 254 case DB_UNKNOWN: 255 default: 256 ret = (__db_unknown_type(env, "DB->stat_print", dbp->type)); 257 break; 258 } 259 260 if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0) 261 ret = t_ret; 262 263 return (ret); 264} 265 266/* 267 * __db_print_all -- 268 * Display debugging DB handle statistics. 269 */ 270static int 271__db_print_all(dbp, flags) 272 DB *dbp; 273 u_int32_t flags; 274{ 275 static const FN fn[] = { 276 { DB_AM_CHKSUM, "DB_AM_CHKSUM" }, 277 { DB_AM_COMPENSATE, "DB_AM_COMPENSATE" }, 278 { DB_AM_CREATED, "DB_AM_CREATED" }, 279 { DB_AM_CREATED_MSTR, "DB_AM_CREATED_MSTR" }, 280 { DB_AM_DBM_ERROR, "DB_AM_DBM_ERROR" }, 281 { DB_AM_DELIMITER, "DB_AM_DELIMITER" }, 282 { DB_AM_DISCARD, "DB_AM_DISCARD" }, 283 { DB_AM_DUP, "DB_AM_DUP" }, 284 { DB_AM_DUPSORT, "DB_AM_DUPSORT" }, 285 { DB_AM_ENCRYPT, "DB_AM_ENCRYPT" }, 286 { DB_AM_FIXEDLEN, "DB_AM_FIXEDLEN" }, 287 { DB_AM_INMEM, "DB_AM_INMEM" }, 288 { DB_AM_IN_RENAME, "DB_AM_IN_RENAME" }, 289 { DB_AM_NOT_DURABLE, "DB_AM_NOT_DURABLE" }, 290 { DB_AM_OPEN_CALLED, "DB_AM_OPEN_CALLED" }, 291 { DB_AM_PAD, "DB_AM_PAD" }, 292 { DB_AM_PGDEF, "DB_AM_PGDEF" }, 293 { DB_AM_RDONLY, "DB_AM_RDONLY" }, 294 { DB_AM_READ_UNCOMMITTED, "DB_AM_READ_UNCOMMITTED" }, 295 { DB_AM_RECNUM, "DB_AM_RECNUM" }, 296 { DB_AM_RECOVER, "DB_AM_RECOVER" }, 297 { DB_AM_RENUMBER, "DB_AM_RENUMBER" }, 298 { DB_AM_REVSPLITOFF, "DB_AM_REVSPLITOFF" }, 299 { DB_AM_SECONDARY, "DB_AM_SECONDARY" }, 300 { DB_AM_SNAPSHOT, "DB_AM_SNAPSHOT" }, 301 { DB_AM_SUBDB, "DB_AM_SUBDB" }, 302 { DB_AM_SWAP, "DB_AM_SWAP" }, 303 { DB_AM_TXN, "DB_AM_TXN" }, 304 { DB_AM_VERIFYING, "DB_AM_VERIFYING" }, 305 { 0, NULL } 306 }; 307 ENV *env; 308 char time_buf[CTIME_BUFLEN]; 309 310 env = dbp->env; 311 312 __db_msg(env, "%s", DB_GLOBAL(db_line)); 313 __db_msg(env, "DB handle information:"); 314 STAT_ULONG("Page size", dbp->pgsize); 315 STAT_ISSET("Append recno", dbp->db_append_recno); 316 STAT_ISSET("Feedback", dbp->db_feedback); 317 STAT_ISSET("Dup compare", dbp->dup_compare); 318 STAT_ISSET("App private", dbp->app_private); 319 STAT_ISSET("DbEnv", dbp->env); 320 STAT_STRING("Type", __db_dbtype_to_string(dbp->type)); 321 322 __mutex_print_debug_single(env, "Thread mutex", dbp->mutex, flags); 323 324 STAT_STRING("File", dbp->fname); 325 STAT_STRING("Database", dbp->dname); 326 STAT_HEX("Open flags", dbp->open_flags); 327 328 __db_print_fileid(env, dbp->fileid, "\tFile ID"); 329 330 STAT_ULONG("Cursor adjust ID", dbp->adj_fileid); 331 STAT_ULONG("Meta pgno", dbp->meta_pgno); 332 if (dbp->locker != NULL) 333 STAT_ULONG("Locker ID", dbp->locker->id); 334 if (dbp->cur_locker != NULL) 335 STAT_ULONG("Handle lock", dbp->cur_locker->id); 336 if (dbp->associate_locker != NULL) 337 STAT_ULONG("Associate lock", dbp->associate_locker->id); 338 STAT_ULONG("RPC remote ID", dbp->cl_id); 339 340 __db_msg(env, 341 "%.24s\tReplication handle timestamp", 342 dbp->timestamp == 0 ? "0" : __os_ctime(&dbp->timestamp, time_buf)); 343 344 STAT_ISSET("Secondary callback", dbp->s_callback); 345 STAT_ISSET("Primary handle", dbp->s_primary); 346 347 STAT_ISSET("api internal", dbp->api_internal); 348 STAT_ISSET("Btree/Recno internal", dbp->bt_internal); 349 STAT_ISSET("Hash internal", dbp->h_internal); 350 STAT_ISSET("Queue internal", dbp->q_internal); 351 STAT_ISSET("XA internal", dbp->xa_internal); 352 353 __db_prflags(env, NULL, dbp->flags, fn, NULL, "\tFlags"); 354 355 if (dbp->log_filename == NULL) 356 STAT_ISSET("File naming information", dbp->log_filename); 357 else 358 __dbreg_print_fname(env, dbp->log_filename); 359 360 (void)__db_print_cursor(dbp); 361 362 return (0); 363} 364 365/* 366 * __db_print_cursor -- 367 * Display the cursor active and free queues. 368 */ 369static int 370__db_print_cursor(dbp) 371 DB *dbp; 372{ 373 DBC *dbc; 374 ENV *env; 375 int ret, t_ret; 376 377 env = dbp->env; 378 379 __db_msg(env, "%s", DB_GLOBAL(db_line)); 380 __db_msg(env, "DB handle cursors:"); 381 382 ret = 0; 383 MUTEX_LOCK(dbp->env, dbp->mutex); 384 __db_msg(env, "Active queue:"); 385 TAILQ_FOREACH(dbc, &dbp->active_queue, links) 386 if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0) 387 ret = t_ret; 388 __db_msg(env, "Join queue:"); 389 TAILQ_FOREACH(dbc, &dbp->join_queue, links) 390 if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0) 391 ret = t_ret; 392 __db_msg(env, "Free queue:"); 393 TAILQ_FOREACH(dbc, &dbp->free_queue, links) 394 if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0) 395 ret = t_ret; 396 MUTEX_UNLOCK(dbp->env, dbp->mutex); 397 398 return (ret); 399} 400 401static int 402__db_print_citem(dbc) 403 DBC *dbc; 404{ 405 static const FN fn[] = { 406 { DBC_ACTIVE, "DBC_ACTIVE" }, 407 { DBC_DONTLOCK, "DBC_DONTLOCK" }, 408 { DBC_MULTIPLE, "DBC_MULTIPLE" }, 409 { DBC_MULTIPLE_KEY, "DBC_MULTIPLE_KEY" }, 410 { DBC_OPD, "DBC_OPD" }, 411 { DBC_OWN_LID, "DBC_OWN_LID" }, 412 { DBC_READ_COMMITTED, "DBC_READ_COMMITTED" }, 413 { DBC_READ_UNCOMMITTED, "DBC_READ_UNCOMMITTED" }, 414 { DBC_RECOVER, "DBC_RECOVER" }, 415 { DBC_RMW, "DBC_RMW" }, 416 { DBC_TRANSIENT, "DBC_TRANSIENT" }, 417 { DBC_WRITECURSOR, "DBC_WRITECURSOR" }, 418 { DBC_WRITER, "DBC_WRITER" }, 419 { 0, NULL } 420 }; 421 DB *dbp; 422 DBC_INTERNAL *cp; 423 ENV *env; 424 425 dbp = dbc->dbp; 426 env = dbp->env; 427 cp = dbc->internal; 428 429 STAT_POINTER("DBC", dbc); 430 STAT_POINTER("Associated dbp", dbc->dbp); 431 STAT_POINTER("Associated txn", dbc->txn); 432 STAT_POINTER("Internal", cp); 433 STAT_HEX("Default locker ID", dbc->lref == NULL ? 0 : dbc->lref->id); 434 STAT_HEX("Locker", P_TO_ULONG(dbc->locker)); 435 STAT_STRING("Type", __db_dbtype_to_string(dbc->dbtype)); 436 437 STAT_POINTER("Off-page duplicate cursor", cp->opd); 438 STAT_POINTER("Referenced page", cp->page); 439 STAT_ULONG("Root", cp->root); 440 STAT_ULONG("Page number", cp->pgno); 441 STAT_ULONG("Page index", cp->indx); 442 STAT_STRING("Lock mode", __db_lockmode_to_string(cp->lock_mode)); 443 __db_prflags(env, NULL, dbc->flags, fn, NULL, "\tFlags"); 444 445 switch (dbc->dbtype) { 446 case DB_BTREE: 447 case DB_RECNO: 448 __bam_print_cursor(dbc); 449 break; 450 case DB_HASH: 451 __ham_print_cursor(dbc); 452 break; 453 case DB_UNKNOWN: 454 DB_ASSERT(env, dbp->type != DB_UNKNOWN); 455 /* FALLTHROUGH */ 456 case DB_QUEUE: 457 default: 458 break; 459 } 460 return (0); 461} 462 463#else /* !HAVE_STATISTICS */ 464 465int 466__db_stat_pp(dbp, txn, spp, flags) 467 DB *dbp; 468 DB_TXN *txn; 469 void *spp; 470 u_int32_t flags; 471{ 472 COMPQUIET(spp, NULL); 473 COMPQUIET(txn, NULL); 474 COMPQUIET(flags, 0); 475 476 return (__db_stat_not_built(dbp->env)); 477} 478 479int 480__db_stat_print_pp(dbp, flags) 481 DB *dbp; 482 u_int32_t flags; 483{ 484 COMPQUIET(flags, 0); 485 486 return (__db_stat_not_built(dbp->env)); 487} 488#endif 489