1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: txn_stat.c,v 12.28 2008/01/08 20:59:00 bostic Exp $ 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/txn.h" 16 17#ifdef HAVE_STATISTICS 18static int __txn_compare __P((const void *, const void *)); 19static int __txn_print_all __P((ENV *, u_int32_t)); 20static int __txn_print_stats __P((ENV *, u_int32_t)); 21static int __txn_stat __P((ENV *, DB_TXN_STAT **, u_int32_t)); 22static char *__txn_status __P((DB_TXN_ACTIVE *)); 23static void __txn_gid __P((ENV *, DB_MSGBUF *, DB_TXN_ACTIVE *)); 24 25#define XID_FIELD_IS_SET(p) \ 26 ((p)->xa_status != 0 || (p)->status == TXN_PREPARED) 27 28/* 29 * __txn_stat_pp -- 30 * DB_ENV->txn_stat pre/post processing. 31 * 32 * PUBLIC: int __txn_stat_pp __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); 33 */ 34int 35__txn_stat_pp(dbenv, statp, flags) 36 DB_ENV *dbenv; 37 DB_TXN_STAT **statp; 38 u_int32_t flags; 39{ 40 DB_THREAD_INFO *ip; 41 ENV *env; 42 int ret; 43 44 env = dbenv->env; 45 46 ENV_REQUIRES_CONFIG(env, 47 env->tx_handle, "DB_ENV->txn_stat", DB_INIT_TXN); 48 49 if ((ret = __db_fchk(env, 50 "DB_ENV->txn_stat", flags, DB_STAT_CLEAR)) != 0) 51 return (ret); 52 53 ENV_ENTER(env, ip); 54 REPLICATION_WRAP(env, (__txn_stat(env, statp, flags)), 0, ret); 55 ENV_LEAVE(env, ip); 56 return (ret); 57} 58 59/* 60 * __txn_stat -- 61 * ENV->txn_stat. 62 */ 63static int 64__txn_stat(env, statp, flags) 65 ENV *env; 66 DB_TXN_STAT **statp; 67 u_int32_t flags; 68{ 69 DB_TXNMGR *mgr; 70 DB_TXNREGION *region; 71 DB_TXN_STAT *stats; 72 TXN_DETAIL *td; 73 size_t nbytes; 74 u_int32_t maxtxn, ndx; 75 int ret; 76 77 *statp = NULL; 78 mgr = env->tx_handle; 79 region = mgr->reginfo.primary; 80 81 /* 82 * Allocate for the maximum active transactions -- the DB_TXN_ACTIVE 83 * struct is small and the maximum number of active transactions is 84 * not going to be that large. Don't have to lock anything to look 85 * at the region's maximum active transactions value, it's read-only 86 * and never changes after the region is created. 87 * 88 * The maximum active transactions isn't a hard limit, so allocate 89 * some extra room, and don't walk off the end. 90 */ 91 maxtxn = region->maxtxns + (region->maxtxns / 10) + 10; 92 nbytes = sizeof(DB_TXN_STAT) + sizeof(DB_TXN_ACTIVE) * maxtxn; 93 if ((ret = __os_umalloc(env, nbytes, &stats)) != 0) 94 return (ret); 95 96 TXN_SYSTEM_LOCK(env); 97 memcpy(stats, ®ion->stat, sizeof(*stats)); 98 stats->st_last_txnid = region->last_txnid; 99 stats->st_last_ckp = region->last_ckp; 100 stats->st_time_ckp = region->time_ckp; 101 stats->st_txnarray = (DB_TXN_ACTIVE *)&stats[1]; 102 103 for (ndx = 0, 104 td = SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); 105 td != NULL && ndx < maxtxn; 106 td = SH_TAILQ_NEXT(td, links, __txn_detail), ++ndx) { 107 stats->st_txnarray[ndx].txnid = td->txnid; 108 if (td->parent == INVALID_ROFF) 109 stats->st_txnarray[ndx].parentid = TXN_INVALID; 110 else 111 stats->st_txnarray[ndx].parentid = 112 ((TXN_DETAIL *)R_ADDR(&mgr->reginfo, 113 td->parent))->txnid; 114 stats->st_txnarray[ndx].pid = td->pid; 115 stats->st_txnarray[ndx].tid = td->tid; 116 stats->st_txnarray[ndx].lsn = td->begin_lsn; 117 stats->st_txnarray[ndx].read_lsn = td->read_lsn; 118 stats->st_txnarray[ndx].mvcc_ref = td->mvcc_ref; 119 stats->st_txnarray[ndx].status = td->status; 120 stats->st_txnarray[ndx].xa_status = td->xa_status; 121 if (XID_FIELD_IS_SET(td)) 122 memcpy(stats->st_txnarray[ndx].xid, 123 td->xid, sizeof(td->xid)); 124 if (td->name != INVALID_ROFF) { 125 (void)strncpy(stats->st_txnarray[ndx].name, 126 R_ADDR(&mgr->reginfo, td->name), 127 sizeof(stats->st_txnarray[ndx].name) - 1); 128 stats->st_txnarray[ndx].name[ 129 sizeof(stats->st_txnarray[ndx].name) - 1] = '\0'; 130 } else 131 stats->st_txnarray[ndx].name[0] = '\0'; 132 } 133 134 __mutex_set_wait_info(env, region->mtx_region, 135 &stats->st_region_wait, &stats->st_region_nowait); 136 stats->st_regsize = mgr->reginfo.rp->size; 137 if (LF_ISSET(DB_STAT_CLEAR)) { 138 if (!LF_ISSET(DB_STAT_SUBSYSTEM)) 139 __mutex_clear(env, region->mtx_region); 140 memset(®ion->stat, 0, sizeof(region->stat)); 141 region->stat.st_maxtxns = region->maxtxns; 142 region->stat.st_maxnactive = 143 region->stat.st_nactive = stats->st_nactive; 144 region->stat.st_maxnsnapshot = 145 region->stat.st_nsnapshot = stats->st_nsnapshot; 146 } 147 148 TXN_SYSTEM_UNLOCK(env); 149 150 *statp = stats; 151 return (0); 152} 153 154/* 155 * __txn_stat_print_pp -- 156 * DB_ENV->txn_stat_print pre/post processing. 157 * 158 * PUBLIC: int __txn_stat_print_pp __P((DB_ENV *, u_int32_t)); 159 */ 160int 161__txn_stat_print_pp(dbenv, flags) 162 DB_ENV *dbenv; 163 u_int32_t flags; 164{ 165 DB_THREAD_INFO *ip; 166 ENV *env; 167 int ret; 168 169 env = dbenv->env; 170 171 ENV_REQUIRES_CONFIG(env, 172 env->tx_handle, "DB_ENV->txn_stat_print", DB_INIT_TXN); 173 174 if ((ret = __db_fchk(env, "DB_ENV->txn_stat_print", 175 flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0) 176 return (ret); 177 178 ENV_ENTER(env, ip); 179 REPLICATION_WRAP(env, (__txn_stat_print(env, flags)), 0, ret); 180 ENV_LEAVE(env, ip); 181 return (ret); 182} 183 184/* 185 * __txn_stat_print 186 * ENV->txn_stat_print method. 187 * 188 * PUBLIC: int __txn_stat_print __P((ENV *, u_int32_t)); 189 */ 190int 191__txn_stat_print(env, flags) 192 ENV *env; 193 u_int32_t flags; 194{ 195 u_int32_t orig_flags; 196 int ret; 197 198 orig_flags = flags; 199 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); 200 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { 201 ret = __txn_print_stats(env, orig_flags); 202 if (flags == 0 || ret != 0) 203 return (ret); 204 } 205 206 if (LF_ISSET(DB_STAT_ALL) && 207 (ret = __txn_print_all(env, orig_flags)) != 0) 208 return (ret); 209 210 return (0); 211} 212 213/* 214 * __txn_print_stats -- 215 * Display default transaction region statistics. 216 */ 217static int 218__txn_print_stats(env, flags) 219 ENV *env; 220 u_int32_t flags; 221{ 222 DB_ENV *dbenv; 223 DB_MSGBUF mb; 224 DB_TXN_ACTIVE *txn; 225 DB_TXN_STAT *sp; 226 u_int32_t i; 227 int ret; 228 char buf[DB_THREADID_STRLEN], time_buf[CTIME_BUFLEN]; 229 230 dbenv = env->dbenv; 231 232 if ((ret = __txn_stat(env, &sp, flags)) != 0) 233 return (ret); 234 235 if (LF_ISSET(DB_STAT_ALL)) 236 __db_msg(env, "Default transaction region information:"); 237 __db_msg(env, "%lu/%lu\t%s", 238 (u_long)sp->st_last_ckp.file, (u_long)sp->st_last_ckp.offset, 239 sp->st_last_ckp.file == 0 ? 240 "No checkpoint LSN" : "File/offset for last checkpoint LSN"); 241 if (sp->st_time_ckp == 0) 242 __db_msg(env, "0\tNo checkpoint timestamp"); 243 else 244 __db_msg(env, "%.24s\tCheckpoint timestamp", 245 __os_ctime(&sp->st_time_ckp, time_buf)); 246 __db_msg(env, "%#lx\tLast transaction ID allocated", 247 (u_long)sp->st_last_txnid); 248 __db_dl(env, "Maximum number of active transactions configured", 249 (u_long)sp->st_maxtxns); 250 __db_dl(env, "Active transactions", (u_long)sp->st_nactive); 251 __db_dl(env, 252 "Maximum active transactions", (u_long)sp->st_maxnactive); 253 __db_dl(env, 254 "Number of transactions begun", (u_long)sp->st_nbegins); 255 __db_dl(env, 256 "Number of transactions aborted", (u_long)sp->st_naborts); 257 __db_dl(env, 258 "Number of transactions committed", (u_long)sp->st_ncommits); 259 __db_dl(env, "Snapshot transactions", (u_long)sp->st_nsnapshot); 260 __db_dl(env, "Maximum snapshot transactions", 261 (u_long)sp->st_maxnsnapshot); 262 __db_dl(env, 263 "Number of transactions restored", (u_long)sp->st_nrestores); 264 265 __db_dlbytes(env, "Transaction region size", 266 (u_long)0, (u_long)0, (u_long)sp->st_regsize); 267 __db_dl_pct(env, 268 "The number of region locks that required waiting", 269 (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait, 270 sp->st_region_wait + sp->st_region_nowait), NULL); 271 272 qsort(sp->st_txnarray, 273 sp->st_nactive, sizeof(sp->st_txnarray[0]), __txn_compare); 274 __db_msg(env, "Active transactions:"); 275 DB_MSGBUF_INIT(&mb); 276 for (i = 0; i < sp->st_nactive; ++i) { 277 txn = &sp->st_txnarray[i]; 278 __db_msgadd(env, &mb, 279 "\t%lx: %s; pid/thread %s; begin LSN: file/offset %lu/%lu", 280 (u_long)txn->txnid, __txn_status(txn), 281 dbenv->thread_id_string(dbenv, txn->pid, txn->tid, buf), 282 (u_long)txn->lsn.file, (u_long)txn->lsn.offset); 283 if (txn->parentid != 0) 284 __db_msgadd(env, &mb, 285 "; parent: %lx", (u_long)txn->parentid); 286 if (!IS_MAX_LSN(txn->read_lsn)) 287 __db_msgadd(env, &mb, "; read LSN: %lu/%lu", 288 (u_long)txn->read_lsn.file, 289 (u_long)txn->read_lsn.offset); 290 if (txn->mvcc_ref != 0) 291 __db_msgadd(env, &mb, 292 "; mvcc refcount: %lu", (u_long)txn->mvcc_ref); 293 if (txn->name[0] != '\0') 294 __db_msgadd(env, &mb, "; \"%s\"", txn->name); 295 if (XID_FIELD_IS_SET(txn)) 296 __txn_gid(env, &mb, txn); 297 DB_MSGBUF_FLUSH(env, &mb); 298 } 299 300 __os_ufree(env, sp); 301 302 return (0); 303} 304 305/* 306 * __txn_print_all -- 307 * Display debugging transaction region statistics. 308 */ 309static int 310__txn_print_all(env, flags) 311 ENV *env; 312 u_int32_t flags; 313{ 314 static const FN fn[] = { 315 { TXN_IN_RECOVERY, "TXN_IN_RECOVERY" }, 316 { 0, NULL } 317 }; 318 DB_TXNMGR *mgr; 319 DB_TXNREGION *region; 320 char time_buf[CTIME_BUFLEN]; 321 322 mgr = env->tx_handle; 323 region = mgr->reginfo.primary; 324 325 TXN_SYSTEM_LOCK(env); 326 327 __db_print_reginfo(env, &mgr->reginfo, "Transaction", flags); 328 329 __db_msg(env, "%s", DB_GLOBAL(db_line)); 330 __db_msg(env, "DB_TXNMGR handle information:"); 331 __mutex_print_debug_single(env, "DB_TXNMGR mutex", mgr->mutex, flags); 332 __db_dl(env, 333 "Number of transactions discarded", (u_long)mgr->n_discards); 334 335 __db_msg(env, "%s", DB_GLOBAL(db_line)); 336 __db_msg(env, "DB_TXNREGION handle information:"); 337 __mutex_print_debug_single( 338 env, "DB_TXNREGION region mutex", region->mtx_region, flags); 339 STAT_ULONG("Maximum number of active txns", region->maxtxns); 340 STAT_HEX("Last transaction ID allocated", region->last_txnid); 341 STAT_HEX("Current maximum unused ID", region->cur_maxid); 342 343 __mutex_print_debug_single( 344 env, "checkpoint mutex", region->mtx_ckp, flags); 345 STAT_LSN("Last checkpoint LSN", ®ion->last_ckp); 346 __db_msg(env, 347 "%.24s\tLast checkpoint timestamp", 348 region->time_ckp == 0 ? "0" : 349 __os_ctime(®ion->time_ckp, time_buf)); 350 351 __db_prflags(env, NULL, region->flags, fn, NULL, "\tFlags"); 352 353 __db_msg(env, "%s", DB_GLOBAL(db_line)); 354 __db_msg(env, "XA information:"); 355 STAT_LONG("XA RMID", env->xa_rmid); 356 /* 357 * XXX 358 * Display list of XA transactions in the ENV handle. 359 */ 360 361 TXN_SYSTEM_UNLOCK(env); 362 363 return (0); 364} 365 366static char * 367__txn_status(txn) 368 DB_TXN_ACTIVE *txn; 369{ 370 switch (txn->xa_status) { 371 case 0: 372 switch (txn->status) { 373 case TXN_ABORTED: 374 return ("aborted"); 375 case TXN_COMMITTED: 376 return ("committed"); 377 case TXN_PREPARED: 378 return ("prepared"); 379 case TXN_RUNNING: 380 return ("running"); 381 default: 382 break; 383 } 384 break; 385 case TXN_XA_ABORTED: 386 return ("XA aborted"); 387 case TXN_XA_DEADLOCKED: 388 return ("XA deadlocked"); 389 case TXN_XA_ENDED: 390 return ("XA ended"); 391 case TXN_XA_PREPARED: 392 return ("XA prepared"); 393 case TXN_XA_STARTED: 394 return ("XA started"); 395 case TXN_XA_SUSPENDED: 396 return ("XA suspended"); 397 default: 398 break; 399 } 400 return ("unknown state"); 401} 402 403static void 404__txn_gid(env, mbp, txn) 405 ENV *env; 406 DB_MSGBUF *mbp; 407 DB_TXN_ACTIVE *txn; 408{ 409 u_int32_t v, *xp; 410 u_int i; 411 int cnt; 412 413 __db_msgadd(env, mbp, "\n\tGID/XID:"); 414 for (cnt = 0, xp = (u_int32_t *)txn->xid, i = 0;;) { 415 memcpy(&v, xp++, sizeof(u_int32_t)); 416 __db_msgadd(env, mbp, "%#lx ", (u_long)v); 417 if ((i += sizeof(u_int32_t)) >= DB_XIDDATASIZE) 418 break; 419 if (++cnt == 4) { 420 DB_MSGBUF_FLUSH(env, mbp); 421 __db_msgadd(env, mbp, "\t\t"); 422 cnt = 0; 423 } 424 } 425} 426 427static int 428__txn_compare(a1, b1) 429 const void *a1, *b1; 430{ 431 const DB_TXN_ACTIVE *a, *b; 432 433 a = a1; 434 b = b1; 435 436 if (a->txnid > b->txnid) 437 return (1); 438 if (a->txnid < b->txnid) 439 return (-1); 440 return (0); 441} 442 443#else /* !HAVE_STATISTICS */ 444 445int 446__txn_stat_pp(dbenv, statp, flags) 447 DB_ENV *dbenv; 448 DB_TXN_STAT **statp; 449 u_int32_t flags; 450{ 451 COMPQUIET(statp, NULL); 452 COMPQUIET(flags, 0); 453 454 return (__db_stat_not_built(dbenv->env)); 455} 456 457int 458__txn_stat_print_pp(dbenv, flags) 459 DB_ENV *dbenv; 460 u_int32_t flags; 461{ 462 COMPQUIET(flags, 0); 463 464 return (__db_stat_not_built(dbenv->env)); 465} 466#endif 467