00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: lock__region_8c-source.html,v 1.1 2008年06月08日 10:20:00 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <ctype.h> 00018 #include <errno.h> 00019 #include <string.h> 00020 #endif 00021 00022 #ifdef HAVE_RPC 00023 #include "db_server.h" 00024 #endif 00025 00026 #include "db_int.h" 00027 #include "db_shash.h" 00028 #include "lock.h" 00029 00030 #ifdef HAVE_RPC 00031 #include "gen_client_ext.h" 00032 #include "rpc_client_ext.h" 00033 #endif 00034 #undef __lock_init 00035 00036 static void __lock_dump_locker (DB_LOCKTAB *, DB_LOCKER *, FILE *); 00037 static void __lock_dump_object (DB_LOCKTAB *, DB_LOCKOBJ *, FILE *); 00038 static const char * 00039 __lock_dump_status __P((db_status_t)); 00040 00041 static int __lock_init __P((DB_ENV *, DB_LOCKTAB *)); 00042 static size_t 00043 __lock_region_size __P((DB_ENV *)); 00044 static int __lock_set_lk_conflicts __P((DB_ENV *, u_int8_t *, int)); 00045 static int __lock_set_lk_detect __P((DB_ENV *, u_int32_t)); 00046 static int __lock_set_lk_max __P((DB_ENV *, u_int32_t)); 00047 00048 /* 00049 * This conflict array is used for concurrent db access (CDB). It 00050 * uses the same locks as the db_rw_conflict array, but adds an IW 00051 * mode to be used for write cursors. 00052 */ 00053 static u_int8_t const db_cdb_conflicts[] = { 00054 /* N R W IW */ 00055 /* N */ 0, 0, 0, 0, 00056 /* R */ 0, 0, 1, 0, 00057 /* W */ 0, 1, 1, 1, 00058 /* IW */ 0, 0, 1, 1 00059 }; 00060 00061 /* 00062 * CDB___lock_dbenv_create -- 00063 * Lock specific creation of the DB_ENV structure. 00064 * 00065 * PUBLIC: void CDB___lock_dbenv_create __P((DB_ENV *)); 00066 */ 00067 void 00068 CDB___lock_dbenv_create(dbenv) 00069 DB_ENV *dbenv; 00070 { 00071 dbenv->lk_max = DB_LOCK_DEFAULT_N; 00072 00073 dbenv->set_lk_conflicts = __lock_set_lk_conflicts; 00074 dbenv->set_lk_detect = __lock_set_lk_detect; 00075 dbenv->set_lk_max = __lock_set_lk_max; 00076 00077 #ifdef HAVE_RPC 00078 /* 00079 * If we have a client, overwrite what we just set up to point 00080 * to the client functions. 00081 */ 00082 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { 00083 dbenv->set_lk_conflicts = __dbcl_set_lk_conflict; 00084 dbenv->set_lk_detect = __dbcl_set_lk_detect; 00085 dbenv->set_lk_max = __dbcl_set_lk_max; 00086 } 00087 #endif 00088 } 00089 00090 /* 00091 * CDB___lock_dbenv_close -- 00092 * Lock specific destruction of the DB_ENV structure. 00093 * 00094 * PUBLIC: void CDB___lock_dbenv_close __P((DB_ENV *)); 00095 */ 00096 void 00097 CDB___lock_dbenv_close(dbenv) 00098 DB_ENV *dbenv; 00099 { 00100 if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC) && dbenv->lk_conflicts != NULL) { 00101 CDB___os_free(dbenv->lk_conflicts, 00102 dbenv->lk_modes * dbenv->lk_modes); 00103 dbenv->lk_conflicts = NULL; 00104 } 00105 } 00106 00107 /* 00108 * __lock_set_lk_conflicts 00109 * Set the conflicts matrix. 00110 */ 00111 static int 00112 __lock_set_lk_conflicts(dbenv, lk_conflicts, lk_modes) 00113 DB_ENV *dbenv; 00114 u_int8_t *lk_conflicts; 00115 int lk_modes; 00116 { 00117 int ret; 00118 00119 ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_conflicts"); 00120 00121 if (dbenv->lk_conflicts != NULL) { 00122 CDB___os_free(dbenv->lk_conflicts, 00123 dbenv->lk_modes * dbenv->lk_modes); 00124 dbenv->lk_conflicts = NULL; 00125 } 00126 if ((ret = CDB___os_malloc(dbenv, 00127 lk_modes * lk_modes, NULL, &dbenv->lk_conflicts)) != 0) 00128 return (ret); 00129 memcpy(dbenv->lk_conflicts, lk_conflicts, lk_modes * lk_modes); 00130 dbenv->lk_modes = lk_modes; 00131 00132 return (0); 00133 } 00134 00135 /* 00136 * __lock_set_lk_detect 00137 * Set the automatic deadlock detection. 00138 */ 00139 static int 00140 __lock_set_lk_detect(dbenv, lk_detect) 00141 DB_ENV *dbenv; 00142 u_int32_t lk_detect; 00143 { 00144 ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_detect"); 00145 00146 switch (lk_detect) { 00147 case DB_LOCK_DEFAULT: 00148 case DB_LOCK_OLDEST: 00149 case DB_LOCK_RANDOM: 00150 case DB_LOCK_YOUNGEST: 00151 break; 00152 default: 00153 return (EINVAL); 00154 } 00155 dbenv->lk_detect = lk_detect; 00156 return (0); 00157 } 00158 00159 /* 00160 * __lock_set_lk_max 00161 * Set the lock table size. 00162 */ 00163 static int 00164 __lock_set_lk_max(dbenv, lk_max) 00165 DB_ENV *dbenv; 00166 u_int32_t lk_max; 00167 { 00168 ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_max"); 00169 00170 dbenv->lk_max = lk_max; 00171 return (0); 00172 } 00173 00174 /* 00175 * CDB___lock_open -- 00176 * Internal version of lock_open: only called from DB_ENV->open. 00177 * 00178 * PUBLIC: int CDB___lock_open __P((DB_ENV *)); 00179 */ 00180 int 00181 CDB___lock_open(dbenv) 00182 DB_ENV *dbenv; 00183 { 00184 DB_LOCKREGION *region; 00185 DB_LOCKTAB *lt; 00186 size_t size; 00187 int ret; 00188 00189 /* Create the lock table structure. */ 00190 if ((ret = CDB___os_calloc(dbenv, 1, sizeof(DB_LOCKTAB), <)) != 0) 00191 return (ret); 00192 lt->dbenv = dbenv; 00193 00194 /* Join/create the lock region. */ 00195 lt->reginfo.id = REG_ID_LOCK; 00196 lt->reginfo.mode = dbenv->db_mode; 00197 if (F_ISSET(dbenv, DB_ENV_CREATE)) 00198 F_SET(<->reginfo, REGION_CREATE_OK); 00199 size = __lock_region_size(dbenv); 00200 if ((ret = CDB___db_r_attach(dbenv, <->reginfo, size)) != 0) 00201 goto err; 00202 00203 /* If we created the region, initialize it. */ 00204 if (F_ISSET(<->reginfo, REGION_CREATE)) 00205 if ((ret = __lock_init(dbenv, lt)) != 0) 00206 goto err; 00207 00208 /* Set the local addresses. */ 00209 region = lt->reginfo.primary = 00210 R_ADDR(<->reginfo, lt->reginfo.rp->primary); 00211 00212 /* Check for incompatible automatic deadlock detection requests. */ 00213 if (dbenv->lk_detect != DB_LOCK_NORUN) { 00214 if (region->detect != DB_LOCK_NORUN && 00215 dbenv->lk_detect != DB_LOCK_DEFAULT && 00216 region->detect != dbenv->lk_detect) { 00217 CDB___db_err(dbenv, 00218 "lock_open: incompatible deadlock detector mode"); 00219 ret = EINVAL; 00220 goto err; 00221 } 00222 00223 /* 00224 * Upgrade if our caller wants automatic detection, and it 00225 * was not currently being done, whether or not we created 00226 * the region. 00227 */ 00228 if (region->detect == DB_LOCK_NORUN) 00229 region->detect = dbenv->lk_detect; 00230 } 00231 00232 /* Set remaining pointers into region. */ 00233 lt->conflicts = (u_int8_t *)R_ADDR(<->reginfo, region->conf_off); 00234 lt->obj_tab = (DB_HASHTAB *)R_ADDR(<->reginfo, region->obj_off); 00235 lt->locker_tab = (DB_HASHTAB *)R_ADDR(<->reginfo, region->locker_off); 00236 00237 R_UNLOCK(dbenv, <->reginfo); 00238 00239 dbenv->lk_handle = lt; 00240 return (0); 00241 00242 err: if (lt->reginfo.addr != NULL) { 00243 if (F_ISSET(<->reginfo, REGION_CREATE)) 00244 F_SET(lt->reginfo.rp, REG_DEAD); 00245 R_UNLOCK(dbenv, <->reginfo); 00246 (void)CDB___db_r_detach(dbenv, <->reginfo, 0); 00247 } 00248 CDB___os_free(lt, sizeof(*lt)); 00249 return (ret); 00250 }; 00251 00252 /* 00253 * __lock_init -- 00254 * Initialize the lock region. 00255 */ 00256 static int 00257 __lock_init(dbenv, lt) 00258 DB_ENV *dbenv; 00259 DB_LOCKTAB *lt; 00260 { 00261 const u_int8_t *lk_conflicts; 00262 struct __db_lock *lp; 00263 DB_LOCKER *lidp; 00264 DB_LOCKOBJ *op; 00265 DB_LOCKREGION *region; 00266 u_int32_t i, lk_modes, nelements; 00267 u_int8_t *addr; 00268 int ret; 00269 00270 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00271 sizeof(DB_LOCKREGION), 0, <->reginfo.primary)) != 0) 00272 goto mem_err; 00273 lt->reginfo.rp->primary = R_OFFSET(<->reginfo, lt->reginfo.primary); 00274 region = lt->reginfo.primary; 00275 memset(region, 0, sizeof(*region)); 00276 00277 /* Select a conflict matrix if none specified. */ 00278 if (dbenv->lk_modes == 0) 00279 if (LOCKING(dbenv)) { 00280 lk_modes = DB_LOCK_RW_N + 1; 00281 lk_conflicts = db_cdb_conflicts; 00282 } else { 00283 lk_modes = DB_LOCK_RW_N; 00284 lk_conflicts = CDB_db_rw_conflicts; 00285 } 00286 else { 00287 lk_modes = dbenv->lk_modes; 00288 lk_conflicts = dbenv->lk_conflicts; 00289 } 00290 00291 region->id = 0; 00292 region->need_dd = 0; 00293 region->detect = DB_LOCK_NORUN; 00294 region->maxlocks = dbenv->lk_max; 00295 region->table_size = CDB___db_tablesize(dbenv->lk_max); 00296 region->nmodes = lk_modes; 00297 region->nlockers = 0; 00298 region->maxnlockers = 0; 00299 region->nconflicts = 0; 00300 region->nrequests = 0; 00301 region->nreleases = 0; 00302 region->ndeadlocks = 0; 00303 00304 nelements = region->table_size; 00305 00306 /* Allocate room for the conflict matrix and initialize it. */ 00307 if ((ret = 00308 CDB___db_shalloc(lt->reginfo.addr, lk_modes * lk_modes, 0, &addr)) != 0) 00309 goto mem_err; 00310 memcpy(addr, lk_conflicts, lk_modes * lk_modes); 00311 region->conf_off = R_OFFSET(<->reginfo, addr); 00312 00313 /* Allocate room for the object hash table and initialize it. */ 00314 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00315 nelements * sizeof(DB_HASHTAB), 0, &addr)) != 0) 00316 goto mem_err; 00317 CDB___db_hashinit(addr, nelements); 00318 region->obj_off = R_OFFSET(<->reginfo, addr); 00319 00320 /* Allocate room for the locker hash table and initialize it. */ 00321 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00322 nelements * sizeof(DB_HASHTAB), 0, &addr)) != 0) 00323 goto mem_err; 00324 CDB___db_hashinit(addr, nelements); 00325 region->locker_off = R_OFFSET(<->reginfo, addr); 00326 00327 /* 00328 * Initialize locks onto a free list. Initialize and lock the mutex 00329 * so that when we need to block, all we need do is try to acquire 00330 * the mutex. 00331 */ 00332 SH_TAILQ_INIT(®ion->free_locks); 00333 for (i = 0; i < region->maxlocks; ++i) { 00334 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00335 sizeof(struct __db_lock), MUTEX_ALIGN, &lp)) != 0) 00336 goto mem_err; 00337 lp->status = DB_LSTAT_FREE; 00338 if ((ret = __db_mutex_init(dbenv, &lp->mutex, 00339 R_OFFSET(<->reginfo, &lp->mutex) + DB_FCNTL_OFF_LOCK, 00340 MUTEX_SELF_BLOCK)) != 0) 00341 return (ret); 00342 MUTEX_LOCK(&lp->mutex, lt->dbenv->lockfhp); 00343 SH_TAILQ_INSERT_HEAD(®ion->free_locks, lp, links, __db_lock); 00344 } 00345 00346 /* Initialize objects onto a free list. */ 00347 SH_TAILQ_INIT(®ion->dd_objs); 00348 SH_TAILQ_INIT(®ion->free_objs); 00349 for (i = 0; i < region->maxlocks; ++i) { 00350 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00351 sizeof(DB_LOCKOBJ), 0, &op)) != 0) 00352 goto mem_err; 00353 SH_TAILQ_INSERT_HEAD( 00354 ®ion->free_objs, op, links, __db_lockobj); 00355 } 00356 00357 /* Initialize lockers onto a free list. */ 00358 SH_TAILQ_INIT(®ion->free_lockers); 00359 for (i = 0; i < region->maxlocks; ++i) { 00360 if ((ret = CDB___db_shalloc(lt->reginfo.addr, 00361 sizeof(DB_LOCKER), 0, &lidp)) != 0) { 00362 mem_err: CDB___db_err(dbenv, "Unable to allocate memory for the lock table"); 00363 return (ret); 00364 } 00365 SH_TAILQ_INSERT_HEAD( 00366 ®ion->free_lockers, lidp, links, __db_locker); 00367 } 00368 00369 return (0); 00370 } 00371 00372 /* 00373 * CDB___lock_close -- 00374 * Internal version of lock_close: only called from db_appinit. 00375 * 00376 * PUBLIC: int CDB___lock_close __P((DB_ENV *)); 00377 */ 00378 int 00379 CDB___lock_close(dbenv) 00380 DB_ENV *dbenv; 00381 { 00382 DB_LOCKTAB *lt; 00383 int ret; 00384 00385 lt = dbenv->lk_handle; 00386 00387 /* Detach from the region. */ 00388 ret = CDB___db_r_detach(dbenv, <->reginfo, 0); 00389 00390 CDB___os_free(lt, sizeof(*lt)); 00391 00392 dbenv->lk_handle = NULL; 00393 return (ret); 00394 } 00395 00396 /* 00397 * CDB_lock_stat -- 00398 * Return LOCK statistics. 00399 */ 00400 int 00401 CDB_lock_stat(dbenv, statp, db_malloc) 00402 DB_ENV *dbenv; 00403 DB_LOCK_STAT **statp; 00404 void *(*db_malloc) __P((size_t)); 00405 { 00406 DB_LOCKREGION *region; 00407 DB_LOCKTAB *lt; 00408 DB_LOCK_STAT *stats; 00409 int ret; 00410 00411 #ifdef HAVE_RPC 00412 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00413 return (__dbcl_lock_stat(dbenv, statp, db_malloc)); 00414 #endif 00415 00416 PANIC_CHECK(dbenv); 00417 ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); 00418 00419 *statp = NULL; 00420 00421 lt = dbenv->lk_handle; 00422 00423 if ((ret = CDB___os_malloc(dbenv, sizeof(*stats), db_malloc, &stats)) != 0) 00424 return (ret); 00425 00426 /* Copy out the global statistics. */ 00427 R_LOCK(dbenv, <->reginfo); 00428 00429 region = lt->reginfo.primary; 00430 stats->st_lastid = region->id; 00431 stats->st_maxlocks = region->maxlocks; 00432 stats->st_nmodes = region->nmodes; 00433 stats->st_nlockers = region->nlockers; 00434 stats->st_maxnlockers = region->maxnlockers; 00435 stats->st_nconflicts = region->nconflicts; 00436 stats->st_nrequests = region->nrequests; 00437 stats->st_nreleases = region->nreleases; 00438 stats->st_nnowaits = region->nnowaits; 00439 stats->st_ndeadlocks = region->ndeadlocks; 00440 00441 stats->st_region_wait = lt->reginfo.rp->mutex.mutex_set_wait; 00442 stats->st_region_nowait = lt->reginfo.rp->mutex.mutex_set_nowait; 00443 stats->st_regsize = lt->reginfo.rp->size; 00444 00445 R_UNLOCK(dbenv, <->reginfo); 00446 00447 *statp = stats; 00448 return (0); 00449 } 00450 00451 #define LOCK_DUMP_CONF 0x001 /* Conflict matrix. */ 00452 #define LOCK_DUMP_FREE 0x002 /* Display lock free list. */ 00453 #define LOCK_DUMP_LOCKERS 0x004 /* Display lockers. */ 00454 #define LOCK_DUMP_MEM 0x008 /* Display region memory. */ 00455 #define LOCK_DUMP_OBJECTS 0x010 /* Display objects. */ 00456 #define LOCK_DUMP_ALL 0x01f /* Display all. */ 00457 00458 /* 00459 * CDB___lock_dump_region -- 00460 * 00461 * PUBLIC: void CDB___lock_dump_region __P((DB_ENV *, char *, FILE *)); 00462 */ 00463 void 00464 CDB___lock_dump_region(dbenv, area, fp) 00465 DB_ENV *dbenv; 00466 char *area; 00467 FILE *fp; 00468 { 00469 struct __db_lock *lp; 00470 DB_LOCKER *lip; 00471 DB_LOCKOBJ *op; 00472 DB_LOCKREGION *lrp; 00473 DB_LOCKTAB *lt; 00474 u_int32_t flags, i, j; 00475 int label; 00476 00477 /* Make it easy to call from the debugger. */ 00478 if (fp == NULL) 00479 fp = stderr; 00480 00481 for (flags = 0; *area != '0円'; ++area) 00482 switch (*area) { 00483 case 'A': 00484 LF_SET(LOCK_DUMP_ALL); 00485 break; 00486 case 'c': 00487 LF_SET(LOCK_DUMP_CONF); 00488 break; 00489 case 'f': 00490 LF_SET(LOCK_DUMP_FREE); 00491 break; 00492 case 'l': 00493 LF_SET(LOCK_DUMP_LOCKERS); 00494 break; 00495 case 'm': 00496 LF_SET(LOCK_DUMP_MEM); 00497 break; 00498 case 'o': 00499 LF_SET(LOCK_DUMP_OBJECTS); 00500 break; 00501 } 00502 00503 lt = dbenv->lk_handle; 00504 lrp = lt->reginfo.primary; 00505 LOCKREGION(dbenv, lt); 00506 00507 fprintf(fp, "%s\nLock region parameters\n", DB_LINE); 00508 fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu\n", 00509 "table size", (u_long)lrp->table_size, 00510 "obj_off", (u_long)lrp->obj_off, 00511 "osynch_off", (u_long)lrp->osynch_off, 00512 "locker_off", (u_long)lrp->locker_off, 00513 "lsynch_off", (u_long)lrp->lsynch_off, 00514 "need_dd", (u_long)lrp->need_dd); 00515 00516 if (LF_ISSET(LOCK_DUMP_CONF)) { 00517 fprintf(fp, "\n%s\nConflict matrix\n", DB_LINE); 00518 for (i = 0; i < lrp->nmodes; i++) { 00519 for (j = 0; j < lrp->nmodes; j++) 00520 fprintf(fp, "%lu\t", 00521 (u_long)lt->conflicts[i * lrp->nmodes + j]); 00522 fprintf(fp, "\n"); 00523 } 00524 } 00525 00526 if (LF_ISSET(LOCK_DUMP_LOCKERS)) { 00527 fprintf(fp, "%s\nLocker hash buckets\n", DB_LINE); 00528 for (i = 0; i < lrp->table_size; i++) { 00529 label = 1; 00530 for (lip = 00531 SH_TAILQ_FIRST(<->locker_tab[i], __db_locker); 00532 lip != NULL; 00533 lip = SH_TAILQ_NEXT(lip, links, __db_locker)) { 00534 if (label) { 00535 fprintf(fp, "Bucket %lu:\n", (u_long)i); 00536 label = 0; 00537 } 00538 __lock_dump_locker(lt, lip, fp); 00539 } 00540 } 00541 } 00542 00543 if (LF_ISSET(LOCK_DUMP_OBJECTS)) { 00544 fprintf(fp, "%s\nObject hash buckets\n", DB_LINE); 00545 for (i = 0; i < lrp->table_size; i++) { 00546 label = 1; 00547 for (op = SH_TAILQ_FIRST(<->obj_tab[i], __db_lockobj); 00548 op != NULL; 00549 op = SH_TAILQ_NEXT(op, links, __db_lockobj)) { 00550 if (label) { 00551 fprintf(fp, "Bucket %lu:\n", (u_long)i); 00552 label = 0; 00553 } 00554 __lock_dump_object(lt, op, fp); 00555 } 00556 } 00557 } 00558 00559 if (LF_ISSET(LOCK_DUMP_FREE)) { 00560 fprintf(fp, "%s\nLock free list\n", DB_LINE); 00561 for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock); 00562 lp != NULL; 00563 lp = SH_TAILQ_NEXT(lp, links, __db_lock)) 00564 fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp, 00565 (u_long)lp->holder, (u_long)lp->mode, 00566 __lock_dump_status(lp->status), (u_long)lp->obj); 00567 00568 fprintf(fp, "%s\nObject free list\n", DB_LINE); 00569 for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj); 00570 op != NULL; 00571 op = SH_TAILQ_NEXT(op, links, __db_lockobj)) 00572 fprintf(fp, "0x%lx\n", (u_long)op); 00573 00574 fprintf(fp, "%s\nLocker free list\n", DB_LINE); 00575 for (lip = SH_TAILQ_FIRST(&lrp->free_lockers, __db_locker); 00576 lip != NULL; 00577 lip = SH_TAILQ_NEXT(lip, links, __db_locker)) 00578 fprintf(fp, "0x%lx\n", (u_long)lip); 00579 } 00580 00581 if (LF_ISSET(LOCK_DUMP_MEM)) 00582 CDB___db_shalloc_dump(lt->reginfo.addr, fp); 00583 00584 UNLOCKREGION(dbenv, lt); 00585 } 00586 00587 static void 00588 __lock_dump_locker(lt, lip, fp) 00589 DB_LOCKTAB *lt; 00590 DB_LOCKER *lip; 00591 FILE *fp; 00592 { 00593 struct __db_lock *lp; 00594 00595 fprintf(fp, "L %lx [%ld]", (u_long)lip->id, (long)lip->dd_id); 00596 fprintf(fp, " %s ", F_ISSET(lip, DB_LOCKER_DELETED) ? "(D)" : " "); 00597 00598 if ((lp = SH_LIST_FIRST(&lip->heldby, __db_lock)) == NULL) 00599 fprintf(fp, "\n"); 00600 else 00601 for (; lp != NULL; 00602 lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) 00603 CDB___lock_printlock(lt, lp, 1); 00604 } 00605 00606 static void 00607 __lock_dump_object(lt, op, fp) 00608 DB_LOCKTAB *lt; 00609 DB_LOCKOBJ *op; 00610 FILE *fp; 00611 { 00612 struct __db_lock *lp; 00613 u_int32_t j; 00614 u_int8_t *ptr; 00615 u_int ch; 00616 00617 ptr = SH_DBT_PTR(&op->lockobj); 00618 for (j = 0; j < op->lockobj.size; ptr++, j++) { 00619 ch = *ptr; 00620 fprintf(fp, isprint(ch) ? "%c" : "\\%o", ch); 00621 } 00622 fprintf(fp, "\n"); 00623 00624 fprintf(fp, "H:"); 00625 for (lp = 00626 SH_TAILQ_FIRST(&op->holders, __db_lock); 00627 lp != NULL; 00628 lp = SH_TAILQ_NEXT(lp, links, __db_lock)) 00629 CDB___lock_printlock(lt, lp, 1); 00630 lp = SH_TAILQ_FIRST(&op->waiters, __db_lock); 00631 if (lp != NULL) { 00632 fprintf(fp, "\nW:"); 00633 for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) 00634 CDB___lock_printlock(lt, lp, 1); 00635 } 00636 } 00637 00638 static const char * 00639 __lock_dump_status(status) 00640 db_status_t status; 00641 { 00642 switch (status) { 00643 case DB_LSTAT_ABORTED: 00644 return ("aborted"); 00645 case DB_LSTAT_ERR: 00646 return ("err"); 00647 case DB_LSTAT_FREE: 00648 return ("free"); 00649 case DB_LSTAT_HELD: 00650 return ("held"); 00651 case DB_LSTAT_NOGRANT: 00652 return ("nogrant"); 00653 case DB_LSTAT_PENDING: 00654 return ("pending"); 00655 case DB_LSTAT_WAITING: 00656 return ("waiting"); 00657 } 00658 return ("unknown status"); 00659 } 00660 00661 /* 00662 * __lock_region_size -- 00663 * Return the region size. 00664 */ 00665 static size_t 00666 __lock_region_size(dbenv) 00667 DB_ENV *dbenv; 00668 { 00669 size_t retval; 00670 u_int32_t i, nelements, nlocks; 00671 int gb; 00672 00673 gb = 0; 00674 #ifdef DIAGNOSTIC 00675 /* 00676 * The below precise calculation doesn't leave enough space for guard 00677 * bytes, of which there is one plus whatever alignment wastage for 00678 * each CDB___db_shalloc. Give ourselves some breathing room. 00679 */ 00680 gb = 1; 00681 #endif 00682 00683 nlocks = dbenv->lk_max; 00684 nelements = CDB___db_tablesize(dbenv->lk_max); 00685 00686 /* 00687 * Figure out how much space we're going to need. This list should 00688 * map one-to-one with the CDB___db_shalloc calls in __lock_init. 00689 */ 00690 retval = 0; 00691 retval += ALIGN(sizeof(DB_LOCKREGION) + gb, 1); 00692 retval += ALIGN(dbenv->lk_modes * dbenv->lk_modes + gb, 1); 00693 retval += ALIGN(nelements * (sizeof(DB_HASHTAB) + gb), 1); 00694 retval += ALIGN(nelements * (sizeof(DB_HASHTAB) + gb), 1); 00695 for (i = 0; i < nlocks; ++i) 00696 retval += 00697 ALIGN(sizeof(struct __db_lock) + gb , MUTEX_ALIGN); 00698 for (i = 0; i < nlocks; ++i) 00699 retval += ALIGN(sizeof(DB_LOCKOBJ) + gb , 1); 00700 for (i = 0; i < nlocks; ++i) 00701 retval += ALIGN(sizeof(DB_LOCKER) + gb , 1); 00702 00703 /* 00704 * Aproximate the memory allocation overhead. This breaks the 00705 * abstraction a little, but seems better than a WAG. 00706 */ 00707 retval += nlocks * (2 * sizeof(ssize_t) + sizeof(size_t)); 00708 00709 /* 00710 * Include 16 bytes of string space per lock. DB doesn't use it 00711 * because we pre-allocate lock space for DBTs in the structure. 00712 */ 00713 retval += ALIGN(nlocks * 16, sizeof(size_t)); 00714 00715 /* And we keep getting this wrong, let's be generous. */ 00716 retval += 16 * 1024; 00717 00718 return (retval); 00719 }