Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

lock_stat.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: lock_stat.c,v 12.11 2005/10/07 20:21:31 ubell Exp $
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  * __lock_stat_pp --
00047  *      DB_ENV->lock_stat pre/post processing.
00048  *
00049  * PUBLIC: int __lock_stat_pp __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t));
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  * __lock_stat --
00076  *      DB_ENV->lock_stat.
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         /* Copy out the global statistics. */
00096         LOCK_SYSTEM_LOCK(dbenv);
00097 
00098         region = lt->reginfo.primary;
00099         memcpy(stats, &region->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(&region->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  * __lock_stat_print_pp --
00133  *      DB_ENV->lock_stat_print pre/post processing.
00134  *
00135  * PUBLIC: int __lock_stat_print_pp __P((DB_ENV *, u_int32_t));
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  * __lock_stat_print --
00164  *      DB_ENV->lock_stat_print method.
00165  *
00166  * PUBLIC: int  __lock_stat_print __P((DB_ENV *, u_int32_t));
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  * __lock_print_stats --
00194  *      Display default lock region statistics.
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  * __lock_print_all --
00266  *      Display debugging lock region statistics.
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, &lt->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(&lt->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(&lt->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  * __lock_print_header --
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  * __lock_printlock --
00423  *
00424  * PUBLIC: void __lock_printlock
00425  * PUBLIC:     __P((DB_LOCKTAB *, DB_MSGBUF *mbp, struct __db_lock *, int));
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                 /* Assume this is a DBT lock. */
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(&lt->reginfo, lockobj));
00530                 __db_pr(dbenv, mbp, ptr, lockobj->lockobj.size);
00531         }
00532         DB_MSGBUF_FLUSH(dbenv, mbp);
00533 }
00534 
00535 #else /* !HAVE_STATISTICS */
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

Generated on Sun Dec 25 12:14:40 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2