lock_region.c

Go to the documentation of this file.
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), &lt)) != 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(&lt->reginfo, REGION_CREATE_OK);
00199         size = __lock_region_size(dbenv);
00200         if ((ret = CDB___db_r_attach(dbenv, &lt->reginfo, size)) != 0)
00201                 goto err;
00202 
00203         /* If we created the region, initialize it. */
00204         if (F_ISSET(&lt->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(&lt->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(&lt->reginfo, region->conf_off);
00234         lt->obj_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->obj_off);
00235         lt->locker_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->locker_off);
00236 
00237         R_UNLOCK(dbenv, &lt->reginfo);
00238 
00239         dbenv->lk_handle = lt;
00240         return (0);
00241 
00242 err:    if (lt->reginfo.addr != NULL) {
00243                 if (F_ISSET(&lt->reginfo, REGION_CREATE))
00244                         F_SET(lt->reginfo.rp, REG_DEAD);
00245                 R_UNLOCK(dbenv, &lt->reginfo);
00246                 (void)CDB___db_r_detach(dbenv, &lt->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, &lt->reginfo.primary)) != 0)
00272                 goto mem_err;
00273         lt->reginfo.rp->primary = R_OFFSET(&lt->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(&lt->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(&lt->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(&lt->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(&region->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(&lt->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(&region->free_locks, lp, links, __db_lock);
00344         }
00345 
00346         /* Initialize objects onto a free list.  */
00347         SH_TAILQ_INIT(&region->dd_objs);
00348         SH_TAILQ_INIT(&region->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                     &region->free_objs, op, links, __db_lockobj);
00355         }
00356 
00357         /* Initialize lockers onto a free list.  */
00358         SH_TAILQ_INIT(&region->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                     &region->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, &lt->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, &lt->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, &lt->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(&lt->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(&lt->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 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5