1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/db_am.h" 14#include "dbinc/log.h" 15#include "dbinc/mp.h" 16#include "dbinc/txn.h" 17 18#ifdef HAVE_STATISTICS 19static void __memp_print_bh __P((ENV *, 20 DB_MPOOL *, const char *, BH *, roff_t *)); 21static int __memp_print_all __P((ENV *, u_int32_t)); 22static int __memp_print_stats __P((ENV *, u_int32_t)); 23static int __memp_print_hash __P((ENV *, 24 DB_MPOOL *, REGINFO *, roff_t *, u_int32_t)); 25static int __memp_stat __P((ENV *, 26 DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); 27static void __memp_stat_wait 28 __P((ENV *, REGINFO *, MPOOL *, DB_MPOOL_STAT *, u_int32_t)); 29static int __memp_file_stats __P((ENV *, 30 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 31static int __memp_count_files __P((ENV *, 32 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 33static int __memp_get_files __P((ENV *, 34 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 35static int __memp_print_files __P((ENV *, 36 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 37 38/* 39 * __memp_stat_pp -- 40 * DB_ENV->memp_stat pre/post processing. 41 * 42 * PUBLIC: int __memp_stat_pp 43 * PUBLIC: __P((DB_ENV *, DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); 44 */ 45int 46__memp_stat_pp(dbenv, gspp, fspp, flags) 47 DB_ENV *dbenv; 48 DB_MPOOL_STAT **gspp; 49 DB_MPOOL_FSTAT ***fspp; 50 u_int32_t flags; 51{ 52 DB_THREAD_INFO *ip; 53 ENV *env; 54 int ret; 55 56 env = dbenv->env; 57 58 ENV_REQUIRES_CONFIG(env, 59 env->mp_handle, "DB_ENV->memp_stat", DB_INIT_MPOOL); 60 61 if ((ret = __db_fchk(env, 62 "DB_ENV->memp_stat", flags, DB_STAT_CLEAR)) != 0) 63 return (ret); 64 65 ENV_ENTER(env, ip); 66 REPLICATION_WRAP(env, (__memp_stat(env, gspp, fspp, flags)), 0, ret); 67 ENV_LEAVE(env, ip); 68 return (ret); 69} 70 71/* 72 * __memp_stat -- 73 * ENV->memp_stat 74 */ 75static int 76__memp_stat(env, gspp, fspp, flags) 77 ENV *env; 78 DB_MPOOL_STAT **gspp; 79 DB_MPOOL_FSTAT ***fspp; 80 u_int32_t flags; 81{ 82 DB_MPOOL *dbmp; 83 DB_MPOOL_FSTAT **tfsp; 84 DB_MPOOL_STAT *sp; 85 MPOOL *c_mp, *mp; 86 size_t len; 87 int ret; 88 u_int32_t i, st_bytes, st_gbytes, st_hash_buckets, st_pages; 89 uintmax_t tmp_wait, tmp_nowait; 90 91 dbmp = env->mp_handle; 92 mp = dbmp->reginfo[0].primary; 93 94 /* Global statistics. */ 95 if (gspp != NULL) { 96 *gspp = NULL; 97 98 if ((ret = __os_umalloc(env, sizeof(**gspp), gspp)) != 0) 99 return (ret); 100 memset(*gspp, 0, sizeof(**gspp)); 101 sp = *gspp; 102 103 /* 104 * Initialization and information that is not maintained on 105 * a per-cache basis. Note that configuration information 106 * may be modified at any time, and so we have to lock. 107 */ 108 sp->st_gbytes = mp->stat.st_gbytes; 109 sp->st_bytes = mp->stat.st_bytes; 110 sp->st_pagesize = mp->stat.st_pagesize; 111 sp->st_ncache = mp->nreg; 112 sp->st_max_ncache = mp->max_nreg; 113 sp->st_regsize = dbmp->reginfo[0].rp->size; 114 sp->st_sync_interrupted = mp->stat.st_sync_interrupted; 115 116 MPOOL_SYSTEM_LOCK(env); 117 sp->st_mmapsize = mp->mp_mmapsize; 118 sp->st_maxopenfd = mp->mp_maxopenfd; 119 sp->st_maxwrite = mp->mp_maxwrite; 120 sp->st_maxwrite_sleep = mp->mp_maxwrite_sleep; 121 MPOOL_SYSTEM_UNLOCK(env); 122 123 /* Walk the cache list and accumulate the global information. */ 124 for (i = 0; i < mp->nreg; ++i) { 125 c_mp = dbmp->reginfo[i].primary; 126 127 sp->st_map += c_mp->stat.st_map; 128 sp->st_cache_hit += c_mp->stat.st_cache_hit; 129 sp->st_cache_miss += c_mp->stat.st_cache_miss; 130 sp->st_page_create += c_mp->stat.st_page_create; 131 sp->st_page_in += c_mp->stat.st_page_in; 132 sp->st_page_out += c_mp->stat.st_page_out; 133 sp->st_ro_evict += c_mp->stat.st_ro_evict; 134 sp->st_rw_evict += c_mp->stat.st_rw_evict; 135 sp->st_page_trickle += c_mp->stat.st_page_trickle; 136 sp->st_pages += c_mp->stat.st_pages; 137 /* 138 * st_page_dirty calculated by __memp_stat_hash 139 * st_page_clean calculated here 140 */ 141 __memp_stat_hash( 142 &dbmp->reginfo[i], c_mp, &sp->st_page_dirty); 143 sp->st_page_clean = sp->st_pages - sp->st_page_dirty; 144 sp->st_hash_buckets += c_mp->stat.st_hash_buckets; 145 sp->st_hash_searches += c_mp->stat.st_hash_searches; 146 sp->st_hash_longest += c_mp->stat.st_hash_longest; 147 sp->st_hash_examined += c_mp->stat.st_hash_examined; 148 /* 149 * st_hash_nowait calculated by __memp_stat_wait 150 * st_hash_wait 151 */ 152 __memp_stat_wait( 153 env, &dbmp->reginfo[i], c_mp, sp, flags); 154 __mutex_set_wait_info(env, 155 c_mp->mtx_region, &tmp_wait, &tmp_nowait); 156 sp->st_region_nowait += tmp_nowait; 157 sp->st_region_wait += tmp_wait; 158 sp->st_alloc += c_mp->stat.st_alloc; 159 sp->st_alloc_buckets += c_mp->stat.st_alloc_buckets; 160 if (sp->st_alloc_max_buckets < 161 c_mp->stat.st_alloc_max_buckets) 162 sp->st_alloc_max_buckets = 163 c_mp->stat.st_alloc_max_buckets; 164 sp->st_alloc_pages += c_mp->stat.st_alloc_pages; 165 if (sp->st_alloc_max_pages < 166 c_mp->stat.st_alloc_max_pages) 167 sp->st_alloc_max_pages = 168 c_mp->stat.st_alloc_max_pages; 169 170 if (LF_ISSET(DB_STAT_CLEAR)) { 171 if (!LF_ISSET(DB_STAT_SUBSYSTEM)) 172 __mutex_clear(env, c_mp->mtx_region); 173 174 MPOOL_SYSTEM_LOCK(env); 175 st_bytes = c_mp->stat.st_bytes; 176 st_gbytes = c_mp->stat.st_gbytes; 177 st_hash_buckets = c_mp->stat.st_hash_buckets; 178 st_pages = c_mp->stat.st_pages; 179 memset(&c_mp->stat, 0, sizeof(c_mp->stat)); 180 c_mp->stat.st_bytes = st_bytes; 181 c_mp->stat.st_gbytes = st_gbytes; 182 c_mp->stat.st_hash_buckets = st_hash_buckets; 183 c_mp->stat.st_pages = st_pages; 184 MPOOL_SYSTEM_UNLOCK(env); 185 } 186 } 187 188 /* 189 * We have duplicate statistics fields in per-file structures 190 * and the cache. The counters are only incremented in the 191 * per-file structures, except if a file is flushed from the 192 * mpool, at which time we copy its information into the cache 193 * statistics. We added the cache information above, now we 194 * add the per-file information. 195 */ 196 if ((ret = __memp_walk_files(env, mp, __memp_file_stats, 197 sp, NULL, fspp == NULL ? LF_ISSET(DB_STAT_CLEAR) : 0)) != 0) 198 return (ret); 199 } 200 201 /* Per-file statistics. */ 202 if (fspp != NULL) { 203 *fspp = NULL; 204 205 /* Count the MPOOLFILE structures. */ 206 i = 0; 207 len = 0; 208 if ((ret = __memp_walk_files(env, 209 mp, __memp_count_files, &len, &i, flags)) != 0) 210 return (ret); 211 212 if (i == 0) 213 return (0); 214 len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */ 215 216 /* Allocate space */ 217 if ((ret = __os_umalloc(env, len, fspp)) != 0) 218 return (ret); 219 220 tfsp = *fspp; 221 *tfsp = NULL; 222 223 /* 224 * Files may have been opened since we counted, don't walk 225 * off the end of the allocated space. 226 */ 227 if ((ret = __memp_walk_files(env, 228 mp, __memp_get_files, &tfsp, &i, flags)) != 0) 229 return (ret); 230 231 *++tfsp = NULL; 232 } 233 234 return (0); 235} 236 237static int 238__memp_file_stats(env, mfp, argp, countp, flags) 239 ENV *env; 240 MPOOLFILE *mfp; 241 void *argp; 242 u_int32_t *countp; 243 u_int32_t flags; 244{ 245 DB_MPOOL_STAT *sp; 246 u_int32_t pagesize; 247 248 COMPQUIET(env, NULL); 249 COMPQUIET(countp, NULL); 250 251 sp = argp; 252 253 sp->st_map += mfp->stat.st_map; 254 sp->st_cache_hit += mfp->stat.st_cache_hit; 255 sp->st_cache_miss += mfp->stat.st_cache_miss; 256 sp->st_page_create += mfp->stat.st_page_create; 257 sp->st_page_in += mfp->stat.st_page_in; 258 sp->st_page_out += mfp->stat.st_page_out; 259 if (LF_ISSET(DB_STAT_CLEAR)) { 260 pagesize = mfp->stat.st_pagesize; 261 memset(&mfp->stat, 0, sizeof(mfp->stat)); 262 mfp->stat.st_pagesize = pagesize; 263 } 264 return (0); 265} 266 267static int 268__memp_count_files(env, mfp, argp, countp, flags) 269 ENV *env; 270 MPOOLFILE *mfp; 271 void *argp; 272 u_int32_t *countp; 273 u_int32_t flags; 274{ 275 DB_MPOOL *dbmp; 276 size_t len; 277 278 COMPQUIET(flags, 0); 279 dbmp = env->mp_handle; 280 len = *(size_t *)argp; 281 282 (*countp)++; 283 len += sizeof(DB_MPOOL_FSTAT *) + 284 sizeof(DB_MPOOL_FSTAT) + strlen(__memp_fns(dbmp, mfp)) + 1; 285 286 *(size_t *)argp = len; 287 return (0); 288} 289 290/* 291 * __memp_get_files -- 292 * get file specific statistics 293 * 294 * Build each individual entry. We assume that an array of pointers are 295 * aligned correctly to be followed by an array of structures, which should 296 * be safe (in this particular case, the first element of the structure 297 * is a pointer, so we're doubly safe). The array is followed by space 298 * for the text file names. 299 */ 300static int 301__memp_get_files(env, mfp, argp, countp, flags) 302 ENV *env; 303 MPOOLFILE *mfp; 304 void *argp; 305 u_int32_t *countp; 306 u_int32_t flags; 307{ 308 DB_MPOOL *dbmp; 309 DB_MPOOL_FSTAT **tfsp, *tstruct; 310 char *name, *tname; 311 size_t nlen; 312 u_int32_t pagesize; 313 314 if (*countp == 0) 315 return (0); 316 317 dbmp = env->mp_handle; 318 tfsp = *(DB_MPOOL_FSTAT ***)argp; 319 320 if (*tfsp == NULL) { 321 /* Add 1 to count because we need to skip over the NULL. */ 322 tstruct = (DB_MPOOL_FSTAT *)(tfsp + *countp + 1); 323 tname = (char *)(tstruct + *countp); 324 *tfsp = tstruct; 325 } else { 326 tstruct = *tfsp + 1; 327 tname = (*tfsp)->file_name + strlen((*tfsp)->file_name) + 1; 328 *++tfsp = tstruct; 329 } 330 331 name = __memp_fns(dbmp, mfp); 332 nlen = strlen(name) + 1; 333 memcpy(tname, name, nlen); 334 *tstruct = mfp->stat; 335 tstruct->file_name = tname; 336 337 *(DB_MPOOL_FSTAT ***)argp = tfsp; 338 (*countp)--; 339 340 if (LF_ISSET(DB_STAT_CLEAR)) { 341 pagesize = mfp->stat.st_pagesize; 342 memset(&mfp->stat, 0, sizeof(mfp->stat)); 343 mfp->stat.st_pagesize = pagesize; 344 } 345 return (0); 346} 347 348/* 349 * __memp_stat_print_pp -- 350 * ENV->memp_stat_print pre/post processing. 351 * 352 * PUBLIC: int __memp_stat_print_pp __P((DB_ENV *, u_int32_t)); 353 */ 354int 355__memp_stat_print_pp(dbenv, flags) 356 DB_ENV *dbenv; 357 u_int32_t flags; 358{ 359 DB_THREAD_INFO *ip; 360 ENV *env; 361 int ret; 362 363 env = dbenv->env; 364 365 ENV_REQUIRES_CONFIG(env, 366 env->mp_handle, "DB_ENV->memp_stat_print", DB_INIT_MPOOL); 367 368#define DB_STAT_MEMP_FLAGS \ 369 (DB_STAT_ALL | DB_STAT_CLEAR | DB_STAT_MEMP_HASH) 370 if ((ret = __db_fchk(env, 371 "DB_ENV->memp_stat_print", flags, DB_STAT_MEMP_FLAGS)) != 0) 372 return (ret); 373 374 ENV_ENTER(env, ip); 375 REPLICATION_WRAP(env, (__memp_stat_print(env, flags)), 0, ret); 376 ENV_LEAVE(env, ip); 377 return (ret); 378} 379 380#define FMAP_ENTRIES 200 /* Files we map. */ 381 382/* 383 * __memp_stat_print -- 384 * ENV->memp_stat_print method. 385 * 386 * PUBLIC: int __memp_stat_print __P((ENV *, u_int32_t)); 387 */ 388int 389__memp_stat_print(env, flags) 390 ENV *env; 391 u_int32_t flags; 392{ 393 u_int32_t orig_flags; 394 int ret; 395 396 orig_flags = flags; 397 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); 398 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { 399 ret = __memp_print_stats(env, 400 LF_ISSET(DB_STAT_ALL) ? flags : orig_flags); 401 if (flags == 0 || ret != 0) 402 return (ret); 403 } 404 405 if (LF_ISSET(DB_STAT_ALL | DB_STAT_MEMP_HASH) && 406 (ret = __memp_print_all(env, orig_flags)) != 0) 407 return (ret); 408 409 return (0); 410} 411 412/* 413 * __memp_print_stats -- 414 * Display default mpool region statistics. 415 */ 416static int 417__memp_print_stats(env, flags) 418 ENV *env; 419 u_int32_t flags; 420{ 421 DB_MPOOL_FSTAT **fsp, **tfsp; 422 DB_MPOOL_STAT *gsp; 423 int ret; 424 425 if ((ret = __memp_stat(env, &gsp, &fsp, flags)) != 0) 426 return (ret); 427 428 if (LF_ISSET(DB_STAT_ALL)) 429 __db_msg(env, "Default cache region information:"); 430 __db_dlbytes(env, "Total cache size", 431 (u_long)gsp->st_gbytes, (u_long)0, (u_long)gsp->st_bytes); 432 __db_dl(env, "Number of caches", (u_long)gsp->st_ncache); 433 __db_dl(env, "Maximum number of caches", (u_long)gsp->st_max_ncache); 434 __db_dlbytes(env, "Pool individual cache size", 435 (u_long)0, (u_long)0, (u_long)gsp->st_regsize); 436 __db_dlbytes(env, "Maximum memory-mapped file size", 437 (u_long)0, (u_long)0, (u_long)gsp->st_mmapsize); 438 STAT_LONG("Maximum open file descriptors", gsp->st_maxopenfd); 439 STAT_LONG("Maximum sequential buffer writes", gsp->st_maxwrite); 440 STAT_LONG("Sleep after writing maximum sequential buffers", 441 gsp->st_maxwrite_sleep); 442 __db_dl(env, 443 "Requested pages mapped into the process' address space", 444 (u_long)gsp->st_map); 445 __db_dl_pct(env, "Requested pages found in the cache", 446 (u_long)gsp->st_cache_hit, DB_PCT( 447 gsp->st_cache_hit, gsp->st_cache_hit + gsp->st_cache_miss), NULL); 448 __db_dl(env, "Requested pages not found in the cache", 449 (u_long)gsp->st_cache_miss); 450 __db_dl(env, 451 "Pages created in the cache", (u_long)gsp->st_page_create); 452 __db_dl(env, "Pages read into the cache", (u_long)gsp->st_page_in); 453 __db_dl(env, "Pages written from the cache to the backing file", 454 (u_long)gsp->st_page_out); 455 __db_dl(env, "Clean pages forced from the cache", 456 (u_long)gsp->st_ro_evict); 457 __db_dl(env, "Dirty pages forced from the cache", 458 (u_long)gsp->st_rw_evict); 459 __db_dl(env, "Dirty pages written by trickle-sync thread", 460 (u_long)gsp->st_page_trickle); 461 __db_dl(env, "Current total page count", 462 (u_long)gsp->st_pages); 463 __db_dl(env, "Current clean page count", 464 (u_long)gsp->st_page_clean); 465 __db_dl(env, "Current dirty page count", 466 (u_long)gsp->st_page_dirty); 467 __db_dl(env, "Number of hash buckets used for page location", 468 (u_long)gsp->st_hash_buckets); 469 __db_dl(env, "Assumed page size used", 470 (u_long)gsp->st_pagesize); 471 __db_dl(env, 472 "Total number of times hash chains searched for a page", 473 (u_long)gsp->st_hash_searches); 474 __db_dl(env, "The longest hash chain searched for a page", 475 (u_long)gsp->st_hash_longest); 476 __db_dl(env, 477 "Total number of hash chain entries checked for page", 478 (u_long)gsp->st_hash_examined); 479 __db_dl_pct(env, 480 "The number of hash bucket locks that required waiting", 481 (u_long)gsp->st_hash_wait, DB_PCT( 482 gsp->st_hash_wait, gsp->st_hash_wait + gsp->st_hash_nowait), NULL); 483 __db_dl_pct(env, 484 "The maximum number of times any hash bucket lock was waited for", 485 (u_long)gsp->st_hash_max_wait, DB_PCT(gsp->st_hash_max_wait, 486 gsp->st_hash_max_wait + gsp->st_hash_max_nowait), NULL); 487 __db_dl_pct(env, 488 "The number of region locks that required waiting", 489 (u_long)gsp->st_region_wait, DB_PCT(gsp->st_region_wait, 490 gsp->st_region_wait + gsp->st_region_nowait), NULL); 491 __db_dl(env, "The number of buffers frozen", 492 (u_long)gsp->st_mvcc_frozen); 493 __db_dl(env, "The number of buffers thawed", 494 (u_long)gsp->st_mvcc_thawed); 495 __db_dl(env, "The number of frozen buffers freed", 496 (u_long)gsp->st_mvcc_freed); 497 __db_dl(env, "The number of page allocations", (u_long)gsp->st_alloc); 498 __db_dl(env, 499 "The number of hash buckets examined during allocations", 500 (u_long)gsp->st_alloc_buckets); 501 __db_dl(env, 502 "The maximum number of hash buckets examined for an allocation", 503 (u_long)gsp->st_alloc_max_buckets); 504 __db_dl(env, "The number of pages examined during allocations", 505 (u_long)gsp->st_alloc_pages); 506 __db_dl(env, "The max number of pages examined for an allocation", 507 (u_long)gsp->st_alloc_max_pages); 508 __db_dl(env, "Threads waited on page I/O", (u_long)gsp->st_io_wait); 509 __db_dl(env, "The number of times a sync is interrupted", 510 (u_long)gsp->st_sync_interrupted); 511 512 for (tfsp = fsp; fsp != NULL && *tfsp != NULL; ++tfsp) { 513 if (LF_ISSET(DB_STAT_ALL)) 514 __db_msg(env, "%s", DB_GLOBAL(db_line)); 515 __db_msg(env, "Pool File: %s", (*tfsp)->file_name); 516 __db_dl(env, "Page size", (u_long)(*tfsp)->st_pagesize); 517 __db_dl(env, 518 "Requested pages mapped into the process' address space", 519 (u_long)(*tfsp)->st_map); 520 __db_dl_pct(env, "Requested pages found in the cache", 521 (u_long)(*tfsp)->st_cache_hit, DB_PCT((*tfsp)->st_cache_hit, 522 (*tfsp)->st_cache_hit + (*tfsp)->st_cache_miss), NULL); 523 __db_dl(env, "Requested pages not found in the cache", 524 (u_long)(*tfsp)->st_cache_miss); 525 __db_dl(env, "Pages created in the cache", 526 (u_long)(*tfsp)->st_page_create); 527 __db_dl(env, "Pages read into the cache", 528 (u_long)(*tfsp)->st_page_in); 529 __db_dl(env, 530 "Pages written from the cache to the backing file", 531 (u_long)(*tfsp)->st_page_out); 532 } 533 534 __os_ufree(env, fsp); 535 __os_ufree(env, gsp); 536 return (0); 537} 538 539/* 540 * __memp_print_all -- 541 * Display debugging mpool region statistics. 542 */ 543static int 544__memp_print_all(env, flags) 545 ENV *env; 546 u_int32_t flags; 547{ 548 static const FN cfn[] = { 549 { DB_MPOOL_NOFILE, "DB_MPOOL_NOFILE" }, 550 { DB_MPOOL_UNLINK, "DB_MPOOL_UNLINK" }, 551 { 0, NULL } 552 }; 553 DB_MPOOL *dbmp; 554 DB_MPOOLFILE *dbmfp; 555 MPOOL *mp; 556 roff_t fmap[FMAP_ENTRIES + 1]; 557 u_int32_t i, cnt; 558 int ret; 559 560 dbmp = env->mp_handle; 561 mp = dbmp->reginfo[0].primary; 562 ret = 0; 563 564 MPOOL_SYSTEM_LOCK(env); 565 566 __db_print_reginfo(env, dbmp->reginfo, "Mpool", flags); 567 __db_msg(env, "%s", DB_GLOBAL(db_line)); 568 569 __db_msg(env, "MPOOL structure:"); 570 __mutex_print_debug_single( 571 env, "MPOOL region mutex", mp->mtx_region, flags); 572 STAT_LSN("Maximum checkpoint LSN", &mp->lsn); 573 STAT_ULONG("Hash table entries", mp->htab_buckets); 574 STAT_ULONG("Hash table last-checked", mp->last_checked); 575 STAT_ULONG("Hash table LRU count", mp->lru_count); 576 STAT_ULONG("Put counter", mp->put_counter); 577 578 __db_msg(env, "%s", DB_GLOBAL(db_line)); 579 __db_msg(env, "DB_MPOOL handle information:"); 580 __mutex_print_debug_single( 581 env, "DB_MPOOL handle mutex", dbmp->mutex, flags); 582 STAT_ULONG("Underlying cache regions", mp->nreg); 583 584 __db_msg(env, "%s", DB_GLOBAL(db_line)); 585 __db_msg(env, "DB_MPOOLFILE structures:"); 586 for (cnt = 0, dbmfp = TAILQ_FIRST(&dbmp->dbmfq); 587 dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q), ++cnt) { 588 __db_msg(env, "File #%lu: %s: per-process, %s", 589 (u_long)cnt + 1, __memp_fn(dbmfp), 590 F_ISSET(dbmfp, MP_READONLY) ? "readonly" : "read/write"); 591 STAT_ULONG("Reference count", dbmfp->ref); 592 STAT_ULONG("Pinned block reference count", dbmfp->ref); 593 STAT_ULONG("Clear length", dbmfp->clear_len); 594 __db_print_fileid(env, dbmfp->fileid, "\tID"); 595 STAT_ULONG("File type", dbmfp->ftype); 596 STAT_ULONG("LSN offset", dbmfp->lsn_offset); 597 STAT_ULONG("Max gbytes", dbmfp->gbytes); 598 STAT_ULONG("Max bytes", dbmfp->bytes); 599 STAT_ULONG("Cache priority", dbmfp->priority); 600 STAT_POINTER("mmap address", dbmfp->addr); 601 STAT_ULONG("mmap length", dbmfp->len); 602 __db_prflags(env, NULL, dbmfp->flags, cfn, NULL, "\tFlags"); 603 __db_print_fh(env, "File handle", dbmfp->fhp, flags); 604 } 605 606 __db_msg(env, "%s", DB_GLOBAL(db_line)); 607 __db_msg(env, "MPOOLFILE structures:"); 608 cnt = 0; 609 ret = __memp_walk_files(env, mp, __memp_print_files, fmap, &cnt, flags); 610 MPOOL_SYSTEM_UNLOCK(env); 611 if (ret != 0) 612 return (ret); 613 614 if (cnt < FMAP_ENTRIES) 615 fmap[cnt] = INVALID_ROFF; 616 else 617 fmap[FMAP_ENTRIES] = INVALID_ROFF; 618 619 /* Dump the individual caches. */ 620 for (i = 0; i < mp->nreg; ++i) { 621 __db_msg(env, "%s", DB_GLOBAL(db_line)); 622 __db_msg(env, "Cache #%d:", i + 1); 623 if (i > 0) 624 __env_alloc_print(&dbmp->reginfo[i], flags); 625 if ((ret = __memp_print_hash( 626 env, dbmp, &dbmp->reginfo[i], fmap, flags)) != 0) 627 break; 628 } 629 630 return (ret); 631} 632 633static int 634__memp_print_files(env, mfp, argp, countp, flags) 635 ENV *env; 636 MPOOLFILE *mfp; 637 void *argp; 638 u_int32_t *countp; 639 u_int32_t flags; 640{ 641 roff_t *fmap; 642 DB_MPOOL *dbmp; 643 u_int32_t mfp_flags; 644 static const FN fn[] = { 645 { MP_CAN_MMAP, "MP_CAN_MMAP" }, 646 { MP_DIRECT, "MP_DIRECT" }, 647 { MP_EXTENT, "MP_EXTENT" }, 648 { MP_FAKE_DEADFILE, "deadfile" }, 649 { MP_FAKE_FILEWRITTEN, "file written" }, 650 { MP_FAKE_NB, "no backing file" }, 651 { MP_FAKE_UOC, "unlink on close" }, 652 { MP_NOT_DURABLE, "not durable" }, 653 { MP_TEMP, "MP_TEMP" }, 654 { 0, NULL } 655 }; 656 657 dbmp = env->mp_handle; 658 fmap = argp; 659 660 __db_msg(env, "File #%d: %s", *countp + 1, __memp_fns(dbmp, mfp)); 661 __mutex_print_debug_single(env, "Mutex", mfp->mutex, flags); 662 663 MUTEX_LOCK(env, mfp->mutex); 664 STAT_ULONG("Reference count", mfp->mpf_cnt); 665 STAT_ULONG("Block count", mfp->block_cnt); 666 STAT_ULONG("Last page number", mfp->last_pgno); 667 STAT_ULONG("Original last page number", mfp->orig_last_pgno); 668 STAT_ULONG("Maximum page number", mfp->maxpgno); 669 STAT_LONG("Type", mfp->ftype); 670 STAT_LONG("Priority", mfp->priority); 671 STAT_LONG("Page's LSN offset", mfp->lsn_off); 672 STAT_LONG("Page's clear length", mfp->clear_len); 673 674 __db_print_fileid(env, 675 R_ADDR(dbmp->reginfo, mfp->fileid_off), "\tID"); 676 677 mfp_flags = 0; 678 if (mfp->deadfile) 679 FLD_SET(mfp_flags, MP_FAKE_DEADFILE); 680 if (mfp->file_written) 681 FLD_SET(mfp_flags, MP_FAKE_FILEWRITTEN); 682 if (mfp->no_backing_file) 683 FLD_SET(mfp_flags, MP_FAKE_NB); 684 if (mfp->unlink_on_close) 685 FLD_SET(mfp_flags, MP_FAKE_UOC); 686 __db_prflags(env, NULL, mfp_flags, fn, NULL, "\tFlags"); 687 688 if (*countp < FMAP_ENTRIES) 689 fmap[*countp] = R_OFFSET(dbmp->reginfo, mfp); 690 (*countp)++; 691 MUTEX_UNLOCK(env, mfp->mutex); 692 return (0); 693} 694 695/* 696 * __memp_print_hash -- 697 * Display hash bucket statistics for a cache. 698 */ 699static int 700__memp_print_hash(env, dbmp, reginfo, fmap, flags) 701 ENV *env; 702 DB_MPOOL *dbmp; 703 REGINFO *reginfo; 704 roff_t *fmap; 705 u_int32_t flags; 706{ 707 BH *bhp, *vbhp; 708 DB_MPOOL_HASH *hp; 709 DB_MSGBUF mb; 710 MPOOL *c_mp; 711 u_int32_t bucket; 712 713 c_mp = reginfo->primary; 714 DB_MSGBUF_INIT(&mb); 715 716 /* Display the hash table list of BH's. */ 717 __db_msg(env, 718 "BH hash table (%lu hash slots)", (u_long)c_mp->htab_buckets); 719 __db_msg(env, "bucket #: priority, I/O wait, [mutex]"); 720 __db_msg(env, "\tpageno, file, ref, LSN, address, priority, flags"); 721 722 for (hp = R_ADDR(reginfo, c_mp->htab), 723 bucket = 0; bucket < c_mp->htab_buckets; ++hp, ++bucket) { 724 MUTEX_READLOCK(env, hp->mtx_hash); 725 if ((bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh)) != NULL) { 726 __db_msgadd(env, &mb, 727 "bucket %lu: %lu (%lu dirty)", 728 (u_long)bucket, (u_long)hp->hash_io_wait, 729 (u_long)atomic_read(&hp->hash_page_dirty)); 730 if (hp->hash_frozen != 0) 731 __db_msgadd(env, &mb, "(MVCC %lu/%lu/%lu) ", 732 (u_long)hp->hash_frozen, 733 (u_long)hp->hash_thawed, 734 (u_long)hp->hash_frozen_freed); 735 __mutex_print_debug_stats( 736 env, &mb, hp->mtx_hash, flags); 737 DB_MSGBUF_FLUSH(env, &mb); 738 } 739 for (; bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) { 740 __memp_print_bh(env, dbmp, NULL, bhp, fmap); 741 742 /* Print the version chain, if it exists. */ 743 for (vbhp = SH_CHAIN_PREV(bhp, vc, __bh); 744 vbhp != NULL; 745 vbhp = SH_CHAIN_PREV(vbhp, vc, __bh)) { 746 __memp_print_bh(env, dbmp, 747 " next:\t", vbhp, fmap); 748 } 749 } 750 MUTEX_UNLOCK(env, hp->mtx_hash); 751 } 752 753 return (0); 754} 755 756/* 757 * __memp_print_bh -- 758 * Display a BH structure. 759 */ 760static void 761__memp_print_bh(env, dbmp, prefix, bhp, fmap) 762 ENV *env; 763 DB_MPOOL *dbmp; 764 const char *prefix; 765 BH *bhp; 766 roff_t *fmap; 767{ 768 static const FN fn[] = { 769 { BH_CALLPGIN, "callpgin" }, 770 { BH_DIRTY, "dirty" }, 771 { BH_DIRTY_CREATE, "created" }, 772 { BH_DISCARD, "discard" }, 773 { BH_EXCLUSIVE, "exclusive" }, 774 { BH_FREED, "freed" }, 775 { BH_FROZEN, "frozen" }, 776 { BH_TRASH, "trash" }, 777 { BH_THAWED, "thawed" }, 778 { 0, NULL } 779 }; 780 DB_MSGBUF mb; 781 int i; 782 783 DB_MSGBUF_INIT(&mb); 784 785 if (prefix != NULL) 786 __db_msgadd(env, &mb, "%s", prefix); 787 else 788 __db_msgadd(env, &mb, "\t"); 789 790 for (i = 0; i < FMAP_ENTRIES; ++i) 791 if (fmap[i] == INVALID_ROFF || fmap[i] == bhp->mf_offset) 792 break; 793 794 if (fmap[i] == INVALID_ROFF) 795 __db_msgadd(env, &mb, "%5lu, %lu, ", 796 (u_long)bhp->pgno, (u_long)bhp->mf_offset); 797 else 798 __db_msgadd( 799 env, &mb, "%5lu, #%d, ", (u_long)bhp->pgno, i + 1); 800 801 __db_msgadd(env, &mb, "%2lu, %lu/%lu", (u_long)atomic_read(&bhp->ref), 802 F_ISSET(bhp, BH_FROZEN) ? 0 : (u_long)LSN(bhp->buf).file, 803 F_ISSET(bhp, BH_FROZEN) ? 0 : (u_long)LSN(bhp->buf).offset); 804 if (bhp->td_off != INVALID_ROFF) 805 __db_msgadd(env, &mb, " (@%lu/%lu)", 806 (u_long)VISIBLE_LSN(env, bhp)->file, 807 (u_long)VISIBLE_LSN(env, bhp)->offset); 808 __db_msgadd(env, &mb, ", %#08lx, %lu", 809 (u_long)R_OFFSET(dbmp->reginfo, bhp), (u_long)bhp->priority); 810 __db_prflags(env, &mb, bhp->flags, fn, " (", ")"); 811 DB_MSGBUF_FLUSH(env, &mb); 812} 813 814/* 815 * __memp_stat_wait -- 816 * Total hash bucket wait stats into the region. 817 */ 818static void 819__memp_stat_wait(env, reginfo, mp, mstat, flags) 820 ENV *env; 821 REGINFO *reginfo; 822 MPOOL *mp; 823 DB_MPOOL_STAT *mstat; 824 u_int32_t flags; 825{ 826 DB_MPOOL_HASH *hp; 827 u_int32_t i; 828 uintmax_t tmp_nowait, tmp_wait; 829 830 mstat->st_hash_max_wait = 0; 831 hp = R_ADDR(reginfo, mp->htab); 832 for (i = 0; i < mp->htab_buckets; i++, hp++) { 833 __mutex_set_wait_info( 834 env, hp->mtx_hash, &tmp_wait, &tmp_nowait); 835 mstat->st_hash_nowait += tmp_nowait; 836 mstat->st_hash_wait += tmp_wait; 837 if (tmp_wait > mstat->st_hash_max_wait) { 838 mstat->st_hash_max_wait = tmp_wait; 839 mstat->st_hash_max_nowait = tmp_nowait; 840 } 841 if (LF_ISSET(DB_STAT_CLEAR | 842 DB_STAT_SUBSYSTEM) == DB_STAT_CLEAR) 843 __mutex_clear(env, hp->mtx_hash); 844 845 mstat->st_io_wait += hp->hash_io_wait; 846 mstat->st_mvcc_frozen += hp->hash_frozen; 847 mstat->st_mvcc_thawed += hp->hash_thawed; 848 mstat->st_mvcc_freed += hp->hash_frozen_freed; 849 if (LF_ISSET(DB_STAT_CLEAR)) { 850 hp->hash_io_wait = 0; 851 hp->hash_frozen = 0; 852 hp->hash_thawed = 0; 853 hp->hash_frozen_freed = 0; 854 } 855 } 856} 857 858#else /* !HAVE_STATISTICS */ 859 860int 861__memp_stat_pp(dbenv, gspp, fspp, flags) 862 DB_ENV *dbenv; 863 DB_MPOOL_STAT **gspp; 864 DB_MPOOL_FSTAT ***fspp; 865 u_int32_t flags; 866{ 867 COMPQUIET(gspp, NULL); 868 COMPQUIET(fspp, NULL); 869 COMPQUIET(flags, 0); 870 871 return (__db_stat_not_built(dbenv->env)); 872} 873 874int 875__memp_stat_print_pp(dbenv, flags) 876 DB_ENV *dbenv; 877 u_int32_t flags; 878{ 879 COMPQUIET(flags, 0); 880 881 return (__db_stat_not_built(dbenv->env)); 882} 883#endif 884 885/* 886 * __memp_stat_hash -- 887 * Total hash bucket stats (other than mutex wait) into the region. 888 * 889 * PUBLIC: void __memp_stat_hash __P((REGINFO *, MPOOL *, u_int32_t *)); 890 */ 891void 892__memp_stat_hash(reginfo, mp, dirtyp) 893 REGINFO *reginfo; 894 MPOOL *mp; 895 u_int32_t *dirtyp; 896{ 897 DB_MPOOL_HASH *hp; 898 u_int32_t dirty, i; 899 900 hp = R_ADDR(reginfo, mp->htab); 901 for (i = 0, dirty = 0; i < mp->htab_buckets; i++, hp++) 902 dirty += (u_int32_t)atomic_read(&hp->hash_page_dirty); 903 *dirtyp = dirty; 904} 905