00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <string.h>
00015 #if TIME_WITH_SYS_TIME
00016 #include <sys/time.h>
00017 #include <time.h>
00018 #else
00019 #if HAVE_SYS_TIME_H
00020 #include <sys/time.h>
00021 #else
00022 #include <time.h>
00023 #endif
00024 #endif
00025
00026 #include <ctype.h>
00027 #endif
00028
00029 #include "db_int.h"
00030 #include "dbinc/db_shash.h"
00031 #include "dbinc/db_page.h"
00032 #include "dbinc/lock.h"
00033 #include "dbinc/log.h"
00034 #include "dbinc/db_am.h"
00035
00036 #ifdef HAVE_STATISTICS
00037 static void __lock_dump_locker
00038 __P((DB_ENV *, DB_MSGBUF *, DB_LOCKTAB *, DB_LOCKER *));
00039 static void __lock_dump_object __P((DB_LOCKTAB *, DB_MSGBUF *, DB_LOCKOBJ *));
00040 static int __lock_print_all __P((DB_ENV *, u_int32_t));
00041 static int __lock_print_stats __P((DB_ENV *, u_int32_t));
00042 static void __lock_print_header __P((DB_ENV *));
00043 static int __lock_stat __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t));
00044
00045
00046
00047
00048
00049
00050
00051 int
00052 __lock_stat_pp(dbenv, statp, flags)
00053 DB_ENV *dbenv;
00054 DB_LOCK_STAT **statp;
00055 u_int32_t flags;
00056 {
00057 DB_THREAD_INFO *ip;
00058 int ret;
00059
00060 PANIC_CHECK(dbenv);
00061 ENV_REQUIRES_CONFIG(dbenv,
00062 dbenv->lk_handle, "DB_ENV->lock_stat", DB_INIT_LOCK);
00063
00064 if ((ret = __db_fchk(dbenv,
00065 "DB_ENV->lock_stat", flags, DB_STAT_CLEAR)) != 0)
00066 return (ret);
00067
00068 ENV_ENTER(dbenv, ip);
00069 REPLICATION_WRAP(dbenv, (__lock_stat(dbenv, statp, flags)), ret);
00070 ENV_LEAVE(dbenv, ip);
00071 return (ret);
00072 }
00073
00074
00075
00076
00077
00078 static int
00079 __lock_stat(dbenv, statp, flags)
00080 DB_ENV *dbenv;
00081 DB_LOCK_STAT **statp;
00082 u_int32_t flags;
00083 {
00084 DB_LOCKREGION *region;
00085 DB_LOCKTAB *lt;
00086 DB_LOCK_STAT *stats, tmp;
00087 int ret;
00088
00089 *statp = NULL;
00090 lt = dbenv->lk_handle;
00091
00092 if ((ret = __os_umalloc(dbenv, sizeof(*stats), &stats)) != 0)
00093 return (ret);
00094
00095
00096 LOCK_SYSTEM_LOCK(dbenv);
00097
00098 region = lt->reginfo.primary;
00099 memcpy(stats, ®ion->stat, sizeof(*stats));
00100 stats->st_locktimeout = region->lk_timeout;
00101 stats->st_txntimeout = region->tx_timeout;
00102
00103 __mutex_set_wait_info(dbenv, region->mtx_region,
00104 &stats->st_region_wait, &stats->st_region_nowait);
00105 stats->st_regsize = lt->reginfo.rp->size;
00106 if (LF_ISSET(DB_STAT_CLEAR)) {
00107 tmp = region->stat;
00108 memset(®ion->stat, 0, sizeof(region->stat));
00109 __mutex_clear(dbenv, region->mtx_region);
00110
00111 region->stat.st_id = tmp.st_id;
00112 region->stat.st_cur_maxid = tmp.st_cur_maxid;
00113 region->stat.st_maxlocks = tmp.st_maxlocks;
00114 region->stat.st_maxlockers = tmp.st_maxlockers;
00115 region->stat.st_maxobjects = tmp.st_maxobjects;
00116 region->stat.st_nlocks =
00117 region->stat.st_maxnlocks = tmp.st_nlocks;
00118 region->stat.st_nlockers =
00119 region->stat.st_maxnlockers = tmp.st_nlockers;
00120 region->stat.st_nobjects =
00121 region->stat.st_maxnobjects = tmp.st_nobjects;
00122 region->stat.st_nmodes = tmp.st_nmodes;
00123 }
00124
00125 LOCK_SYSTEM_UNLOCK(dbenv);
00126
00127 *statp = stats;
00128 return (0);
00129 }
00130
00131
00132
00133
00134
00135
00136
00137 int
00138 __lock_stat_print_pp(dbenv, flags)
00139 DB_ENV *dbenv;
00140 u_int32_t flags;
00141 {
00142 DB_THREAD_INFO *ip;
00143 int ret;
00144
00145 PANIC_CHECK(dbenv);
00146 ENV_REQUIRES_CONFIG(dbenv,
00147 dbenv->lk_handle, "DB_ENV->lock_stat_print", DB_INIT_LOCK);
00148
00149 #define DB_STAT_LOCK_FLAGS \
00150 (DB_STAT_ALL | DB_STAT_CLEAR | DB_STAT_LOCK_CONF | \
00151 DB_STAT_LOCK_LOCKERS | DB_STAT_LOCK_OBJECTS | DB_STAT_LOCK_PARAMS)
00152 if ((ret = __db_fchk(dbenv, "DB_ENV->lock_stat_print",
00153 flags, DB_STAT_CLEAR | DB_STAT_LOCK_FLAGS)) != 0)
00154 return (ret);
00155
00156 ENV_ENTER(dbenv, ip);
00157 REPLICATION_WRAP(dbenv, (__lock_stat_print(dbenv, flags)), ret);
00158 ENV_LEAVE(dbenv, ip);
00159 return (ret);
00160 }
00161
00162
00163
00164
00165
00166
00167
00168 int
00169 __lock_stat_print(dbenv, flags)
00170 DB_ENV *dbenv;
00171 u_int32_t flags;
00172 {
00173 u_int32_t orig_flags;
00174 int ret;
00175
00176 orig_flags = flags;
00177 LF_CLR(DB_STAT_CLEAR);
00178 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
00179 ret = __lock_print_stats(dbenv, orig_flags);
00180 if (flags == 0 || ret != 0)
00181 return (ret);
00182 }
00183
00184 if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_CONF | DB_STAT_LOCK_LOCKERS |
00185 DB_STAT_LOCK_OBJECTS | DB_STAT_LOCK_PARAMS) &&
00186 (ret = __lock_print_all(dbenv, orig_flags)) != 0)
00187 return (ret);
00188
00189 return (0);
00190 }
00191
00192
00193
00194
00195
00196 static int
00197 __lock_print_stats(dbenv, flags)
00198 DB_ENV *dbenv;
00199 u_int32_t flags;
00200 {
00201 DB_LOCK_STAT *sp;
00202 int ret;
00203
00204 if ((ret = __lock_stat(dbenv, &sp, flags)) != 0)
00205 return (ret);
00206
00207 if (LF_ISSET(DB_STAT_ALL))
00208 __db_msg(dbenv, "Default locking region information:");
00209 __db_dl(dbenv, "Last allocated locker ID", (u_long)sp->st_id);
00210 __db_msg(dbenv, "%#lx\tCurrent maximum unused locker ID",
00211 (u_long)sp->st_cur_maxid);
00212 __db_dl(dbenv, "Number of lock modes", (u_long)sp->st_nmodes);
00213 __db_dl(dbenv,
00214 "Maximum number of locks possible", (u_long)sp->st_maxlocks);
00215 __db_dl(dbenv,
00216 "Maximum number of lockers possible", (u_long)sp->st_maxlockers);
00217 __db_dl(dbenv, "Maximum number of lock objects possible",
00218 (u_long)sp->st_maxobjects);
00219 __db_dl(dbenv, "Number of current locks", (u_long)sp->st_nlocks);
00220 __db_dl(dbenv, "Maximum number of locks at any one time",
00221 (u_long)sp->st_maxnlocks);
00222 __db_dl(dbenv, "Number of current lockers", (u_long)sp->st_nlockers);
00223 __db_dl(dbenv, "Maximum number of lockers at any one time",
00224 (u_long)sp->st_maxnlockers);
00225 __db_dl(dbenv,
00226 "Number of current lock objects", (u_long)sp->st_nobjects);
00227 __db_dl(dbenv, "Maximum number of lock objects at any one time",
00228 (u_long)sp->st_maxnobjects);
00229 __db_dl(dbenv,
00230 "Total number of locks requested", (u_long)sp->st_nrequests);
00231 __db_dl(dbenv,
00232 "Total number of locks released", (u_long)sp->st_nreleases);
00233 __db_dl(dbenv,
00234 "Total number of locks upgraded", (u_long)sp->st_nupgrade);
00235 __db_dl(dbenv,
00236 "Total number of locks downgraded", (u_long)sp->st_ndowngrade);
00237 __db_dl(dbenv,
00238 "Lock requests not available due to conflicts, for which we waited",
00239 (u_long)sp->st_lock_wait);
00240 __db_dl(dbenv,
00241 "Lock requests not available due to conflicts, for which we did not wait",
00242 (u_long)sp->st_lock_nowait);
00243 __db_dl(dbenv, "Number of deadlocks", (u_long)sp->st_ndeadlocks);
00244 __db_dl(dbenv, "Lock timeout value", (u_long)sp->st_locktimeout);
00245 __db_dl(dbenv, "Number of locks that have timed out",
00246 (u_long)sp->st_nlocktimeouts);
00247 __db_dl(dbenv,
00248 "Transaction timeout value", (u_long)sp->st_txntimeout);
00249 __db_dl(dbenv, "Number of transactions that have timed out",
00250 (u_long)sp->st_ntxntimeouts);
00251
00252 __db_dlbytes(dbenv, "The size of the lock region",
00253 (u_long)0, (u_long)0, (u_long)sp->st_regsize);
00254 __db_dl_pct(dbenv,
00255 "The number of region locks that required waiting",
00256 (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait,
00257 sp->st_region_wait + sp->st_region_nowait), NULL);
00258
00259 __os_ufree(dbenv, sp);
00260
00261 return (0);
00262 }
00263
00264
00265
00266
00267
00268 static int
00269 __lock_print_all(dbenv, flags)
00270 DB_ENV *dbenv;
00271 u_int32_t flags;
00272 {
00273 DB_LOCKER *lip;
00274 DB_LOCKOBJ *op;
00275 DB_LOCKREGION *lrp;
00276 DB_LOCKTAB *lt;
00277 DB_MSGBUF mb;
00278 int i, j;
00279 u_int32_t k;
00280 char buf[64];
00281
00282 lt = dbenv->lk_handle;
00283 lrp = lt->reginfo.primary;
00284 DB_MSGBUF_INIT(&mb);
00285
00286 LOCK_SYSTEM_LOCK(dbenv);
00287
00288 __db_print_reginfo(dbenv, <->reginfo, "Lock");
00289
00290 if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_PARAMS)) {
00291 __db_msg(dbenv, "%s", DB_GLOBAL(db_line));
00292 __db_msg(dbenv, "Lock region parameters:");
00293 __mutex_print_debug_single(dbenv,
00294 "Lock region region mutex", lrp->mtx_region, flags);
00295 STAT_ULONG("locker table size", lrp->locker_t_size);
00296 STAT_ULONG("object table size", lrp->object_t_size);
00297 STAT_ULONG("obj_off", lrp->obj_off);
00298 STAT_ULONG("locker_off", lrp->locker_off);
00299 STAT_ULONG("need_dd", lrp->need_dd);
00300 if (LOCK_TIME_ISVALID(&lrp->next_timeout) &&
00301 strftime(buf, sizeof(buf), "%m-%d-%H:%M:%S",
00302 localtime((time_t*)&lrp->next_timeout.tv_sec)) != 0)
00303 __db_msg(dbenv, "next_timeout: %s.%lu",
00304 buf, (u_long)lrp->next_timeout.tv_usec);
00305 }
00306
00307 if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_CONF)) {
00308 __db_msg(dbenv, "%s", DB_GLOBAL(db_line));
00309 __db_msg(dbenv, "Lock conflict matrix:");
00310 for (i = 0; i < lrp->stat.st_nmodes; i++) {
00311 for (j = 0; j < lrp->stat.st_nmodes; j++)
00312 __db_msgadd(dbenv, &mb, "%lu\t", (u_long)
00313 lt->conflicts[i * lrp->stat.st_nmodes + j]);
00314 DB_MSGBUF_FLUSH(dbenv, &mb);
00315 }
00316 }
00317
00318 if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_LOCKERS)) {
00319 __db_msg(dbenv, "%s", DB_GLOBAL(db_line));
00320 __db_msg(dbenv, "Locks grouped by lockers:");
00321 __lock_print_header(dbenv);
00322 for (k = 0; k < lrp->locker_t_size; k++)
00323 for (lip =
00324 SH_TAILQ_FIRST(<->locker_tab[k], __db_locker);
00325 lip != NULL;
00326 lip = SH_TAILQ_NEXT(lip, links, __db_locker)) {
00327 __lock_dump_locker(dbenv, &mb, lt, lip);
00328 }
00329 }
00330
00331 if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_OBJECTS)) {
00332 __db_msg(dbenv, "%s", DB_GLOBAL(db_line));
00333 __db_msg(dbenv, "Locks grouped by object:");
00334 __lock_print_header(dbenv);
00335 for (k = 0; k < lrp->object_t_size; k++) {
00336 for (op = SH_TAILQ_FIRST(<->obj_tab[k], __db_lockobj);
00337 op != NULL;
00338 op = SH_TAILQ_NEXT(op, links, __db_lockobj)) {
00339 __lock_dump_object(lt, &mb, op);
00340 __db_msg(dbenv, "%s", "");
00341 }
00342 }
00343 }
00344 LOCK_SYSTEM_UNLOCK(dbenv);
00345
00346 return (0);
00347 }
00348
00349 static void
00350 __lock_dump_locker(dbenv, mbp, lt, lip)
00351 DB_ENV *dbenv;
00352 DB_MSGBUF *mbp;
00353 DB_LOCKTAB *lt;
00354 DB_LOCKER *lip;
00355 {
00356 struct __db_lock *lp;
00357 time_t s;
00358 char buf[DB_THREADID_STRLEN];
00359
00360 __db_msgadd(dbenv,
00361 mbp, "%8lx dd=%2ld locks held %-4d write locks %-4d pid/thread %s",
00362 (u_long)lip->id, (long)lip->dd_id, lip->nlocks, lip->nwrites,
00363 dbenv->thread_id_string(dbenv, lip->pid, lip->tid, buf));
00364 __db_msgadd(
00365 dbenv, mbp, "%s", F_ISSET(lip, DB_LOCKER_DELETED) ? "(D)" : " ");
00366 if (LOCK_TIME_ISVALID(&lip->tx_expire)) {
00367 s = (time_t)lip->tx_expire.tv_sec;
00368 if (strftime(buf,
00369 sizeof(buf), "%m-%d-%H:%M:%S", localtime(&s)) != 0)
00370 __db_msgadd(dbenv, mbp, "expires %s.%lu",
00371 buf, (u_long)lip->tx_expire.tv_usec);
00372 }
00373 if (F_ISSET(lip, DB_LOCKER_TIMEOUT))
00374 __db_msgadd(dbenv, mbp, " lk timeout %u", lip->lk_timeout);
00375 if (LOCK_TIME_ISVALID(&lip->lk_expire)) {
00376 s = (time_t)lip->lk_expire.tv_sec;
00377 if (strftime(buf,
00378 sizeof(buf), "%m-%d-%H:%M:%S", localtime(&s)) != 0)
00379 __db_msgadd(dbenv, mbp, " lk expires %s.%lu",
00380 buf, (u_long)lip->lk_expire.tv_usec);
00381 }
00382 DB_MSGBUF_FLUSH(dbenv, mbp);
00383
00384 for (lp = SH_LIST_FIRST(&lip->heldby, __db_lock);
00385 lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock))
00386 __lock_printlock(lt, mbp, lp, 1);
00387 }
00388
00389 static void
00390 __lock_dump_object(lt, mbp, op)
00391 DB_LOCKTAB *lt;
00392 DB_MSGBUF *mbp;
00393 DB_LOCKOBJ *op;
00394 {
00395 struct __db_lock *lp;
00396
00397 for (lp =
00398 SH_TAILQ_FIRST(&op->holders, __db_lock);
00399 lp != NULL;
00400 lp = SH_TAILQ_NEXT(lp, links, __db_lock))
00401 __lock_printlock(lt, mbp, lp, 1);
00402 for (lp =
00403 SH_TAILQ_FIRST(&op->waiters, __db_lock);
00404 lp != NULL;
00405 lp = SH_TAILQ_NEXT(lp, links, __db_lock))
00406 __lock_printlock(lt, mbp, lp, 1);
00407 }
00408
00409
00410
00411
00412 static void
00413 __lock_print_header(dbenv)
00414 DB_ENV *dbenv;
00415 {
00416 __db_msg(dbenv, "%-8s %-10s%-4s %-7s %s",
00417 "Locker", "Mode",
00418 "Count", "Status", "----------------- Object ---------------");
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 void
00428 __lock_printlock(lt, mbp, lp, ispgno)
00429 DB_LOCKTAB *lt;
00430 DB_MSGBUF *mbp;
00431 struct __db_lock *lp;
00432 int ispgno;
00433 {
00434 DB_ENV *dbenv;
00435 DB_LOCKOBJ *lockobj;
00436 DB_MSGBUF mb;
00437 db_pgno_t pgno;
00438 u_int32_t *fidp, type;
00439 u_int8_t *ptr;
00440 char *namep;
00441 const char *mode, *status;
00442
00443 dbenv = lt->dbenv;
00444
00445 if (mbp == NULL) {
00446 DB_MSGBUF_INIT(&mb);
00447 mbp = &mb;
00448 }
00449
00450 switch (lp->mode) {
00451 case DB_LOCK_IREAD:
00452 mode = "IREAD";
00453 break;
00454 case DB_LOCK_IWR:
00455 mode = "IWR";
00456 break;
00457 case DB_LOCK_IWRITE:
00458 mode = "IWRITE";
00459 break;
00460 case DB_LOCK_NG:
00461 mode = "NG";
00462 break;
00463 case DB_LOCK_READ:
00464 mode = "READ";
00465 break;
00466 case DB_LOCK_READ_UNCOMMITTED:
00467 mode = "READ_UNCOMMITTED";
00468 break;
00469 case DB_LOCK_WRITE:
00470 mode = "WRITE";
00471 break;
00472 case DB_LOCK_WWRITE:
00473 mode = "WAS_WRITE";
00474 break;
00475 case DB_LOCK_WAIT:
00476 mode = "WAIT";
00477 break;
00478 default:
00479 mode = "UNKNOWN";
00480 break;
00481 }
00482 switch (lp->status) {
00483 case DB_LSTAT_ABORTED:
00484 status = "ABORT";
00485 break;
00486 case DB_LSTAT_EXPIRED:
00487 status = "EXPIRED";
00488 break;
00489 case DB_LSTAT_FREE:
00490 status = "FREE";
00491 break;
00492 case DB_LSTAT_HELD:
00493 status = "HELD";
00494 break;
00495 case DB_LSTAT_PENDING:
00496 status = "PENDING";
00497 break;
00498 case DB_LSTAT_WAITING:
00499 status = "WAIT";
00500 break;
00501 default:
00502 status = "UNKNOWN";
00503 break;
00504 }
00505 __db_msgadd(dbenv, mbp, "%8lx %-10s %4lu %-7s ",
00506 (u_long)lp->holder, mode, (u_long)lp->refcount, status);
00507
00508 lockobj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
00509 ptr = SH_DBT_PTR(&lockobj->lockobj);
00510 if (ispgno && lockobj->lockobj.size == sizeof(struct __db_ilock)) {
00511
00512 memcpy(&pgno, ptr, sizeof(db_pgno_t));
00513 fidp = (u_int32_t *)(ptr + sizeof(db_pgno_t));
00514 type = *(u_int32_t *)(ptr + sizeof(db_pgno_t) + DB_FILE_ID_LEN);
00515 if (__dbreg_get_name(lt->dbenv, (u_int8_t *)fidp, &namep) != 0)
00516 namep = NULL;
00517 if (namep == NULL)
00518 __db_msgadd(dbenv, mbp, "(%lx %lx %lx %lx %lx) ",
00519 (u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2],
00520 (u_long)fidp[3], (u_long)fidp[4]);
00521 else
00522 __db_msgadd(dbenv, mbp, "%-25s ", namep);
00523 __db_msgadd(dbenv, mbp, "%-7s %7lu",
00524 type == DB_PAGE_LOCK ? "page" :
00525 type == DB_RECORD_LOCK ? "record" : "handle",
00526 (u_long)pgno);
00527 } else {
00528 __db_msgadd(dbenv, mbp, "0x%lx ",
00529 (u_long)R_OFFSET(<->reginfo, lockobj));
00530 __db_pr(dbenv, mbp, ptr, lockobj->lockobj.size);
00531 }
00532 DB_MSGBUF_FLUSH(dbenv, mbp);
00533 }
00534
00535 #else
00536
00537 int
00538 __lock_stat_pp(dbenv, statp, flags)
00539 DB_ENV *dbenv;
00540 DB_LOCK_STAT **statp;
00541 u_int32_t flags;
00542 {
00543 COMPQUIET(statp, NULL);
00544 COMPQUIET(flags, 0);
00545
00546 return (__db_stat_not_built(dbenv));
00547 }
00548
00549 int
00550 __lock_stat_print_pp(dbenv, flags)
00551 DB_ENV *dbenv;
00552 u_int32_t flags;
00553 {
00554 COMPQUIET(flags, 0);
00555
00556 return (__db_stat_not_built(dbenv));
00557 }
00558 #endif