/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996, 1997, 1998, 1999, 2000 * Sleepycat Software. All rights reserved. */ #include "db_config.h" #ifndef lint static const char revid[] = "$Id: lock_stat.c,v 11.4 2000/12/08 20:15:31 ubell Exp $"; #endif /* not lint */ #ifndef NO_SYSTEM_INCLUDES #include #include #endif #ifdef HAVE_RPC #include "db_server.h" #endif #include "db_int.h" #include "db_shash.h" #include "lock.h" #ifdef HAVE_RPC #include "gen_client_ext.h" #include "rpc_client_ext.h" #endif static void __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKER *, FILE *)); static void __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *)); static const char * __lock_dump_status __P((db_status_t)); /* * lock_stat -- * Return LOCK statistics. */ int lock_stat(dbenv, statp, db_malloc) DB_ENV *dbenv; DB_LOCK_STAT **statp; void *(*db_malloc) __P((size_t)); { DB_LOCKREGION *region; DB_LOCKTAB *lt; DB_LOCK_STAT *stats; int ret; #ifdef HAVE_RPC if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) return (__dbcl_lock_stat(dbenv, statp, db_malloc)); #endif PANIC_CHECK(dbenv); ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); *statp = NULL; lt = dbenv->lk_handle; if ((ret = __os_malloc(dbenv, sizeof(*stats), db_malloc, &stats)) != 0) return (ret); /* Copy out the global statistics. */ R_LOCK(dbenv, <->reginfo); region = lt->reginfo.primary; stats->st_lastid = region->id; stats->st_maxlocks = region->maxlocks; stats->st_maxlockers = region->maxlockers; stats->st_maxobjects = region->maxobjects; stats->st_nmodes = region->nmodes; stats->st_nlockers = region->nlockers; stats->st_maxnlockers = region->maxnlockers; stats->st_nobjects = region->nobjects; stats->st_maxnobjects = region->maxnobjects; stats->st_nlocks = region->nlocks; stats->st_maxnlocks = region->maxnlocks; stats->st_nconflicts = region->nconflicts; stats->st_nrequests = region->nrequests; stats->st_nreleases = region->nreleases; stats->st_nnowaits = region->nnowaits; stats->st_ndeadlocks = region->ndeadlocks; stats->st_region_wait = lt->reginfo.rp->mutex.mutex_set_wait; stats->st_region_nowait = lt->reginfo.rp->mutex.mutex_set_nowait; stats->st_regsize = lt->reginfo.rp->size; R_UNLOCK(dbenv, <->reginfo); *statp = stats; return (0); } #define LOCK_DUMP_CONF 0x001 /* Conflict matrix. */ #define LOCK_DUMP_FREE 0x002 /* Display lock free list. */ #define LOCK_DUMP_LOCKERS 0x004 /* Display lockers. */ #define LOCK_DUMP_MEM 0x008 /* Display region memory. */ #define LOCK_DUMP_OBJECTS 0x010 /* Display objects. */ #define LOCK_DUMP_ALL 0x01f /* Display all. */ /* * __lock_dump_region -- * * PUBLIC: void __lock_dump_region __P((DB_ENV *, char *, FILE *)); */ void __lock_dump_region(dbenv, area, fp) DB_ENV *dbenv; char *area; FILE *fp; { struct __db_lock *lp; DB_LOCKER *lip; DB_LOCKOBJ *op; DB_LOCKREGION *lrp; DB_LOCKTAB *lt; u_int32_t flags, i, j; int label; /* Make it easy to call from the debugger. */ if (fp == NULL) fp = stderr; for (flags = 0; *area != '\0'; ++area) switch (*area) { case 'A': LF_SET(LOCK_DUMP_ALL); break; case 'c': LF_SET(LOCK_DUMP_CONF); break; case 'f': LF_SET(LOCK_DUMP_FREE); break; case 'l': LF_SET(LOCK_DUMP_LOCKERS); break; case 'm': LF_SET(LOCK_DUMP_MEM); break; case 'o': LF_SET(LOCK_DUMP_OBJECTS); break; } lt = dbenv->lk_handle; lrp = lt->reginfo.primary; LOCKREGION(dbenv, lt); fprintf(fp, "%s\nLock region parameters\n", DB_LINE); fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu\n", "locker table size", (u_long)lrp->locker_t_size, "object table size", (u_long)lrp->object_t_size, "obj_off", (u_long)lrp->obj_off, "osynch_off", (u_long)lrp->osynch_off, "locker_off", (u_long)lrp->locker_off, "lsynch_off", (u_long)lrp->lsynch_off, "need_dd", (u_long)lrp->need_dd); if (LF_ISSET(LOCK_DUMP_CONF)) { fprintf(fp, "\n%s\nConflict matrix\n", DB_LINE); for (i = 0; i < lrp->nmodes; i++) { for (j = 0; j < lrp->nmodes; j++) fprintf(fp, "%lu\t", (u_long)lt->conflicts[i * lrp->nmodes + j]); fprintf(fp, "\n"); } } if (LF_ISSET(LOCK_DUMP_LOCKERS)) { fprintf(fp, "%s\nLocker hash buckets\n", DB_LINE); for (i = 0; i < lrp->locker_t_size; i++) { label = 1; for (lip = SH_TAILQ_FIRST(<->locker_tab[i], __db_locker); lip != NULL; lip = SH_TAILQ_NEXT(lip, links, __db_locker)) { if (label) { fprintf(fp, "Bucket %lu:\n", (u_long)i); label = 0; } __lock_dump_locker(lt, lip, fp); } } } if (LF_ISSET(LOCK_DUMP_OBJECTS)) { fprintf(fp, "%s\nObject hash buckets\n", DB_LINE); for (i = 0; i < lrp->object_t_size; i++) { label = 1; for (op = SH_TAILQ_FIRST(<->obj_tab[i], __db_lockobj); op != NULL; op = SH_TAILQ_NEXT(op, links, __db_lockobj)) { if (label) { fprintf(fp, "Bucket %lu:\n", (u_long)i); label = 0; } __lock_dump_object(lt, op, fp); } } } if (LF_ISSET(LOCK_DUMP_FREE)) { fprintf(fp, "%s\nLock free list\n", DB_LINE); for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock); lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp, (u_long)lp->holder, (u_long)lp->mode, __lock_dump_status(lp->status), (u_long)lp->obj); fprintf(fp, "%s\nObject free list\n", DB_LINE); for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj); op != NULL; op = SH_TAILQ_NEXT(op, links, __db_lockobj)) fprintf(fp, "0x%lx\n", (u_long)op); fprintf(fp, "%s\nLocker free list\n", DB_LINE); for (lip = SH_TAILQ_FIRST(&lrp->free_lockers, __db_locker); lip != NULL; lip = SH_TAILQ_NEXT(lip, links, __db_locker)) fprintf(fp, "0x%lx\n", (u_long)lip); } if (LF_ISSET(LOCK_DUMP_MEM)) __db_shalloc_dump(lt->reginfo.addr, fp); UNLOCKREGION(dbenv, lt); } static void __lock_dump_locker(lt, lip, fp) DB_LOCKTAB *lt; DB_LOCKER *lip; FILE *fp; { struct __db_lock *lp; fprintf(fp, "L %lx [%ld]", (u_long)lip->id, (long)lip->dd_id); fprintf(fp, " %s ", F_ISSET(lip, DB_LOCKER_DELETED) ? "(D)" : " "); if ((lp = SH_LIST_FIRST(&lip->heldby, __db_lock)) == NULL) fprintf(fp, "\n"); else for (; lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) __lock_printlock(lt, lp, 1); } static void __lock_dump_object(lt, op, fp) DB_LOCKTAB *lt; DB_LOCKOBJ *op; FILE *fp; { struct __db_lock *lp; u_int32_t j; u_int8_t *ptr; u_int ch; ptr = SH_DBT_PTR(&op->lockobj); for (j = 0; j < op->lockobj.size; ptr++, j++) { ch = *ptr; fprintf(fp, isprint(ch) ? "%c" : "\\%o", ch); } fprintf(fp, "\n"); fprintf(fp, "H:"); for (lp = SH_TAILQ_FIRST(&op->holders, __db_lock); lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) __lock_printlock(lt, lp, 1); lp = SH_TAILQ_FIRST(&op->waiters, __db_lock); if (lp != NULL) { fprintf(fp, "\nW:"); for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) __lock_printlock(lt, lp, 1); } } static const char * __lock_dump_status(status) db_status_t status; { switch (status) { case DB_LSTAT_ABORTED: return ("aborted"); case DB_LSTAT_ERR: return ("err"); case DB_LSTAT_FREE: return ("free"); case DB_LSTAT_HELD: return ("held"); case DB_LSTAT_NOGRANT: return ("nogrant"); case DB_LSTAT_PENDING: return ("pending"); case DB_LSTAT_WAITING: return ("waiting"); } return ("unknown status"); }