about summary refs log tree commit diff
path: root/db2/lock
diff options
context:
space:
mode:
Diffstat (limited to 'db2/lock')
-rw-r--r--db2/lock/lock.c666
-rw-r--r--db2/lock/lock_conflict.c4
-rw-r--r--db2/lock/lock_deadlock.c30
-rw-r--r--db2/lock/lock_region.c726
-rw-r--r--db2/lock/lock_util.c93
5 files changed, 840 insertions, 679 deletions
diff --git a/db2/lock/lock.c b/db2/lock/lock.c
index 0846d3c29f..3d20e0d65b 100644
--- a/db2/lock/lock.c
+++ b/db2/lock/lock.c
@@ -1,28 +1,21 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *	Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock.c	10.43 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)lock.c	10.52 (Sleepycat) 5/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
 
 #include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #endif
 
 #include "db_int.h"
@@ -34,248 +27,15 @@ static const char sccsid[] = "@(#)lock.c	10.43 (Sleepycat) 1/8/98";
 #include "db_am.h"
 
 static void __lock_checklocker __P((DB_LOCKTAB *, struct __db_lock *, int));
-static int  __lock_count_locks __P((DB_LOCKREGION *));
-static int  __lock_count_objs __P((DB_LOCKREGION *));
-static int  __lock_create __P((const char *, int, DB_ENV *));
 static void __lock_freeobj __P((DB_LOCKTAB *, DB_LOCKOBJ *));
-static int  __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, int, const DBT *,
-    db_lockmode_t, struct __db_lock **));
-static int  __lock_grow_region __P((DB_LOCKTAB *, int, size_t));
+static int  __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, u_int32_t,
+    const DBT *, db_lockmode_t, struct __db_lock **));
 static int  __lock_put_internal __P((DB_LOCKTAB *, struct __db_lock *, int));
 static void __lock_remove_waiter
     __P((DB_LOCKTAB *, DB_LOCKOBJ *, struct __db_lock *, db_status_t));
-static void __lock_reset_region __P((DB_LOCKTAB *));
-static int  __lock_validate_region __P((DB_LOCKTAB *));
-#ifdef DEBUG
-static void __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *));
-static void __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *));
-static void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int));
-#endif
-
-/*
- * Create and initialize a lock region in shared memory.
- */
-
-/*
- * __lock_create --
- *	Create the lock region.  Returns an errno.  In most cases,
- * the errno should be that returned by __db_ropen, in which case
- * an EAGAIN means that we should retry, and an EEXIST means that
- * the region exists and we didn't need to create it.  Any other
- * sort of errno should be treated as a system error, leading to a
- * failure of the original interface call.
- */
-static int
-__lock_create(path, mode, dbenv)
-	const char *path;
-	int mode;
-	DB_ENV *dbenv;
-{
-	struct __db_lock *lp;
-	struct lock_header *tq_head;
-	struct obj_header *obj_head;
-	DB_LOCKOBJ *op;
-	DB_LOCKREGION *lrp;
-	u_int maxlocks;
-	u_int32_t i;
-	int fd, lock_modes, nelements, ret;
-	const u_int8_t *conflicts;
-	u_int8_t *curaddr;
-
-	maxlocks = dbenv == NULL || dbenv->lk_max == 0 ?
-	    DB_LOCK_DEFAULT_N : dbenv->lk_max;
-	lock_modes = dbenv == NULL || dbenv->lk_modes == 0 ?
-	    DB_LOCK_RW_N : dbenv->lk_modes;
-	conflicts = dbenv == NULL || dbenv->lk_conflicts == NULL ?
-	    db_rw_conflicts : dbenv->lk_conflicts;
-
-	if ((ret =
-	    __db_rcreate(dbenv, DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE, mode,
-	    LOCK_REGION_SIZE(lock_modes, maxlocks, __db_tablesize(maxlocks)),
-	    0, &fd, &lrp)) != 0)
-		return (ret);
-
-	/* Region exists; now initialize it. */
-	lrp->table_size = __db_tablesize(maxlocks);
-	lrp->magic = DB_LOCKMAGIC;
-	lrp->version = DB_LOCKVERSION;
-	lrp->id = 0;
-	lrp->maxlocks = maxlocks;
-	lrp->need_dd = 0;
-	lrp->detect = DB_LOCK_NORUN;
-	lrp->numobjs = maxlocks;
-	lrp->nlockers = 0;
-	lrp->mem_bytes = ALIGN(STRING_SIZE(maxlocks), sizeof(size_t));
-	lrp->increment = lrp->hdr.size / 2;
-	lrp->nmodes = lock_modes;
-	lrp->nconflicts = 0;
-	lrp->nrequests = 0;
-	lrp->nreleases = 0;
-	lrp->ndeadlocks = 0;
-
-	/*
-	 * As we write the region, we've got to maintain the alignment
-	 * for the structures that follow each chunk.  This information
-	 * ends up being encapsulated both in here as well as in the
-	 * lock.h file for the XXX_SIZE macros.
-	 */
-	/* Initialize conflict matrix. */
-	curaddr = (u_int8_t *)lrp + sizeof(DB_LOCKREGION);
-	memcpy(curaddr, conflicts, lock_modes * lock_modes);
-	curaddr += lock_modes * lock_modes;
-
-	/*
-	 * Initialize hash table.
-	 */
-	curaddr = (u_int8_t *)ALIGNP(curaddr, LOCK_HASH_ALIGN);
-	lrp->hash_off = curaddr - (u_int8_t *)lrp;
-	nelements = lrp->table_size;
-	__db_hashinit(curaddr, nelements);
-	curaddr += nelements * sizeof(DB_HASHTAB);
-
-	/*
-	 * Initialize locks onto a free list. Since locks contains mutexes,
-	 * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT
-	 * boundary.
-	 */
-	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
-	tq_head = &lrp->free_locks;
-	SH_TAILQ_INIT(tq_head);
-
-	for (i = 0; i++ < maxlocks;
-	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
-		lp = (struct __db_lock *)curaddr;
-		lp->status = DB_LSTAT_FREE;
-		SH_TAILQ_INSERT_HEAD(tq_head, lp, links, __db_lock);
-	}
-
-	/* Initialize objects onto a free list.  */
-	obj_head = &lrp->free_objs;
-	SH_TAILQ_INIT(obj_head);
-
-	for (i = 0; i++ < maxlocks; curaddr += sizeof(DB_LOCKOBJ)) {
-		op = (DB_LOCKOBJ *)curaddr;
-		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
-	}
-
-	/*
-	 * Initialize the string space; as for all shared memory allocation
-	 * regions, this requires size_t alignment, since we store the
-	 * lengths of malloc'd areas in the area..
-	 */
-	curaddr = (u_int8_t *)ALIGNP(curaddr, sizeof(size_t));
-	lrp->mem_off = curaddr - (u_int8_t *)lrp;
-	__db_shalloc_init(curaddr, lrp->mem_bytes);
-
-	/* Release the lock. */
-	(void)__db_mutex_unlock(&lrp->hdr.lock, fd);
-
-	/* Now unmap the region. */
-	if ((ret = __db_rclose(dbenv, fd, lrp)) != 0) {
-		(void)lock_unlink(path, 1 /* force */, dbenv);
-		return (ret);
-	}
-
-	return (0);
-}
 
 int
-lock_open(path, flags, mode, dbenv, ltp)
-	const char *path;
-	int flags, mode;
-	DB_ENV *dbenv;
-	DB_LOCKTAB **ltp;
-{
-	DB_LOCKTAB *lt;
-	int ret, retry_cnt;
-
-	/* Validate arguments. */
-#ifdef HAVE_SPINLOCKS
-#define	OKFLAGS	(DB_CREATE | DB_THREAD)
-#else
-#define	OKFLAGS	(DB_CREATE)
-#endif
-	if ((ret = __db_fchk(dbenv, "lock_open", flags, OKFLAGS)) != 0)
-		return (ret);
-
-	/*
-	 * Create the lock table structure.
-	 */
-	if ((lt = (DB_LOCKTAB *)__db_calloc(1, sizeof(DB_LOCKTAB))) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
-		return (ENOMEM);
-	}
-	lt->dbenv = dbenv;
-
-	/*
-	 * Now, create the lock region if it doesn't already exist.
-	 */
-	retry_cnt = 0;
-retry:	if (LF_ISSET(DB_CREATE) &&
-	    (ret = __lock_create(path, mode, dbenv)) != 0)
-		if (ret == EAGAIN && ++retry_cnt < 3) {
-			(void)__db_sleep(1, 0);
-			goto retry;
-		} else if (ret == EEXIST) /* We did not create the region */
-			LF_CLR(DB_CREATE);
-		else
-			goto out;
-
-	/*
-	 * Finally, open the region, map it in, and increment the
-	 * reference count.
-	 */
-	retry_cnt = 0;
-retry1:	if ((ret = __db_ropen(dbenv, DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE,
-	    LF_ISSET(~(DB_CREATE | DB_THREAD)), &lt->fd, &lt->region)) != 0) {
-		if (ret == EAGAIN && ++retry_cnt < 3) {
-			(void)__db_sleep(1, 0);
-			goto retry1;
-		}
-		goto out;
-	 }
-
-	if (lt->region->magic != DB_LOCKMAGIC) {
-		__db_err(dbenv, "lock_open: Bad magic number");
-		ret = EINVAL;
-		goto out;
-	}
-
-	/* Check for automatic deadlock detection. */
-	if (dbenv->lk_detect != DB_LOCK_NORUN) {
-		if (lt->region->detect != DB_LOCK_NORUN &&
-		    dbenv->lk_detect != DB_LOCK_DEFAULT &&
-		    lt->region->detect != dbenv->lk_detect) {
-			__db_err(dbenv,
-			    "lock_open: incompatible deadlock detector mode");
-			ret = EINVAL;
-			goto out;
-		}
-		if (lt->region->detect == DB_LOCK_NORUN)
-			lt->region->detect = dbenv->lk_detect;
-	}
-
-	/* Set up remaining pointers into region. */
-	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
-	lt->hashtab =
-	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
-	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
-	lt->reg_size = lt->region->hdr.size;
-
-	*ltp = lt;
-	return (0);
-
-/* Error handling. */
-out:	if (lt->region != NULL)
-		(void)__db_rclose(lt->dbenv, lt->fd, lt->region);
-	if (LF_ISSET(DB_CREATE))
-		(void)lock_unlink(path, 1, lt->dbenv);
-	__db_free(lt);
-	return (ret);
-}
-
-int
-lock_id (lt, idp)
+lock_id(lt, idp)
 	DB_LOCKTAB *lt;
 	u_int32_t *idp;
 {
@@ -294,8 +54,8 @@ lock_id (lt, idp)
 int
 lock_vec(lt, locker, flags, list, nlist, elistp)
 	DB_LOCKTAB *lt;
-	u_int32_t locker;
-	int flags, nlist;
+	u_int32_t locker, flags;
+	int nlist;
 	DB_LOCKREQ *list, **elistp;
 {
 	struct __db_lock *lp;
@@ -345,7 +105,7 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
 			for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
 			    lp != NULL;
 			    lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
-				if ((ret = __lock_put_internal(lt, lp, 0)) != 0)
+				if ((ret = __lock_put_internal(lt, lp, 1)) != 0)
 					break;
 			}
 			__lock_freeobj(lt, sh_locker);
@@ -436,8 +196,7 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
 int
 lock_get(lt, locker, flags, obj, lock_mode, lock)
 	DB_LOCKTAB *lt;
-	u_int32_t locker;
-	int flags;
+	u_int32_t locker, flags;
 	const DBT *obj;
 	db_lockmode_t lock_mode;
 	DB_LOCK *lock;
@@ -496,35 +255,6 @@ lock_put(lt, lock)
 	return (ret);
 }
 
-int
-lock_close(lt)
-	DB_LOCKTAB *lt;
-{
-	int ret;
-
-	if ((ret = __db_rclose(lt->dbenv, lt->fd, lt->region)) != 0)
-		return (ret);
-
-	/* Free lock table. */
-	__db_free(lt);
-	return (0);
-}
-
-int
-lock_unlink(path, force, dbenv)
-	const char *path;
-	int force;
-	DB_ENV *dbenv;
-{
-	return (__db_runlink(dbenv,
-	    DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE, force));
-}
-
-/*
- * XXX This looks like it could be void, but I'm leaving it returning
- * an int because I think it will have to when we go through and add
- * the appropriate error checking for the EINTR on mutexes.
- */
 static int
 __lock_put_internal(lt, lockp, do_all)
 	DB_LOCKTAB *lt;
@@ -593,7 +323,7 @@ __lock_put_internal(lt, lockp, do_all)
 		SH_TAILQ_INSERT_TAIL(&sh_obj->holders, lp_w, links);
 
 		/* Wake up waiter. */
-		(void)__db_mutex_unlock(&lp_w->mutex, lt->fd);
+		(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
 		state_changed = 1;
 	}
 
@@ -626,8 +356,7 @@ __lock_put_internal(lt, lockp, do_all)
 static int
 __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 	DB_LOCKTAB *lt;
-	u_int32_t locker;
-	int flags;
+	u_int32_t locker, flags;
 	const DBT *obj;
 	db_lockmode_t lock_mode;
 	struct __db_lock **lockp;
@@ -741,7 +470,7 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 	 */
 	(void)__db_mutex_init(&newl->mutex,
 	    MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
-	(void)__db_mutex_lock(&newl->mutex, lt->fd);
+	(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
 
 	/*
 	 * Now, insert the lock onto its locker's list.
@@ -772,7 +501,7 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 		if (lrp->detect != DB_LOCK_NORUN)
 			ret = lock_detect(lt, 0, lrp->detect);
 
-		(void)__db_mutex_lock(&newl->mutex, lt->fd);
+		(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
 
 		LOCK_LOCKREGION(lt);
 		if (newl->status != DB_LSTAT_PENDING) {
@@ -802,306 +531,6 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 }
 
 /*
- * This is called at every interface to verify if the region
- * has changed size, and if so, to remap the region in and
- * reset the process pointers.
- */
-static int
-__lock_validate_region(lt)
-	DB_LOCKTAB *lt;
-{
-	int ret;
-
-	if (lt->reg_size == lt->region->hdr.size)
-		return (0);
-
-	/* Grow the region. */
-	if ((ret = __db_rremap(lt->dbenv, lt->region,
-	    lt->reg_size, lt->region->hdr.size, lt->fd, &lt->region)) != 0)
-		return (ret);
-
-	__lock_reset_region(lt);
-
-	return (0);
-}
-
-/*
- * We have run out of space; time to grow the region.
- */
-static int
-__lock_grow_region(lt, which, howmuch)
-	DB_LOCKTAB *lt;
-	int which;
-	size_t howmuch;
-{
-	struct __db_lock *newl;
-	struct lock_header *lock_head;
-	struct obj_header *obj_head;
-	DB_LOCKOBJ *op;
-	DB_LOCKREGION *lrp;
-	float lock_ratio, obj_ratio;
-	size_t incr, oldsize, used;
-	u_int32_t i, newlocks, newmem, newobjs;
-	int ret, usedlocks, usedmem, usedobjs;
-	u_int8_t *curaddr;
-
-	lrp = lt->region;
-	oldsize = lrp->hdr.size;
-	incr = lrp->increment;
-
-	/* Figure out how much of each sort of space we have. */
-	usedmem = lrp->mem_bytes - __db_shalloc_count(lt->mem);
-	usedobjs = lrp->numobjs - __lock_count_objs(lrp);
-	usedlocks = lrp->maxlocks - __lock_count_locks(lrp);
-
-	/*
-	 * Figure out what fraction of the used space belongs to each
-	 * different type of "thing" in the region.  Then partition the
-	 * new space up according to this ratio.
-	 */
-	used = usedmem +
-	    usedlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) +
-	    usedobjs * sizeof(DB_LOCKOBJ);
-
-	lock_ratio = usedlocks *
-	    ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) / (float)used;
-	obj_ratio = usedobjs * sizeof(DB_LOCKOBJ) / (float)used;
-
-	newlocks = (u_int32_t)(lock_ratio *
-	    incr / ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
-	newobjs = (u_int32_t)(obj_ratio * incr / sizeof(DB_LOCKOBJ));
-	newmem = incr -
-	    (newobjs * sizeof(DB_LOCKOBJ) +
-	    newlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
-
-	/*
-	 * Make sure we allocate enough memory for the object being
-	 * requested.
-	 */
-	switch (which) {
-		case DB_LOCK_LOCK:
-			if (newlocks == 0) {
-				newlocks = 10;
-				incr += newlocks * sizeof(struct __db_lock);
-			}
-			break;
-		case DB_LOCK_OBJ:
-			if (newobjs == 0) {
-				newobjs = 10;
-				incr += newobjs * sizeof(DB_LOCKOBJ);
-			}
-			break;
-		case DB_LOCK_MEM:
-			if (newmem < howmuch * 2) {
-				incr += howmuch * 2 - newmem;
-				newmem = howmuch * 2;
-			}
-			break;
-	}
-
-	newmem += ALIGN(incr, sizeof(size_t)) - incr;
-	incr = ALIGN(incr, sizeof(size_t));
-
-	/*
-	 * Since we are going to be allocating locks at the beginning of the
-	 * new chunk, we need to make sure that the chunk is MUTEX_ALIGNMENT
-	 * aligned.  We did not guarantee this when we created the region, so
-	 * we may need to pad the old region by extra bytes to ensure this
-	 * alignment.
-	 */
-	incr += ALIGN(oldsize, MUTEX_ALIGNMENT) - oldsize;
-
-	__db_err(lt->dbenv,
-	    "Growing lock region: %lu locks %lu objs %lu bytes",
-	    (u_long)newlocks, (u_long)newobjs, (u_long)newmem);
-
-	if ((ret = __db_rgrow(lt->dbenv, lt->fd, incr)) != 0)
-		return (ret);
-	if ((ret = __db_rremap(lt->dbenv,
-	    lt->region, oldsize, oldsize + incr, lt->fd, &lt->region)) != 0)
-		return (ret);
-	__lock_reset_region(lt);
-
-	/* Update region parameters. */
-	lrp = lt->region;
-	lrp->increment = incr << 1;
-	lrp->maxlocks += newlocks;
-	lrp->numobjs += newobjs;
-	lrp->mem_bytes += newmem;
-
-	curaddr = (u_int8_t *)lrp + oldsize;
-	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
-
-	/* Put new locks onto the free list. */
-	lock_head = &lrp->free_locks;
-	for (i = 0; i++ < newlocks;
-	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
-		newl = (struct __db_lock *)curaddr;
-		SH_TAILQ_INSERT_HEAD(lock_head, newl, links, __db_lock);
-	}
-
-	/* Put new objects onto the free list.  */
-	obj_head = &lrp->free_objs;
-	for (i = 0; i++ < newobjs; curaddr += sizeof(DB_LOCKOBJ)) {
-		op = (DB_LOCKOBJ *)curaddr;
-		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
-	}
-
-	*((size_t *)curaddr) = newmem - sizeof(size_t);
-	curaddr += sizeof(size_t);
-	__db_shalloc_free(lt->mem, curaddr);
-
-	return (0);
-}
-
-#ifdef DEBUG
-/*
- * __lock_dump_region --
- *
- * PUBLIC: void __lock_dump_region __P((DB_LOCKTAB *, u_int));
- */
-void
-__lock_dump_region(lt, flags)
-	DB_LOCKTAB *lt;
-	u_int flags;
-{
-	struct __db_lock *lp;
-	DB_LOCKOBJ *op;
-	DB_LOCKREGION *lrp;
-	u_int32_t i, j;
-
-	lrp = lt->region;
-
-	printf("Lock region parameters\n");
-	printf("%s:0x%x\t%s:%lu\t%s:%lu\t%s:%lu\n%s:%lu\t%s:%lu\t%s:%lu\t\n",
-	    "magic      ", lrp->magic,
-	    "version    ", (u_long)lrp->version,
-	    "processes  ", (u_long)lrp->hdr.refcnt,
-	    "maxlocks   ", (u_long)lrp->maxlocks,
-	    "table size ", (u_long)lrp->table_size,
-	    "nmodes     ", (u_long)lrp->nmodes,
-	    "numobjs    ", (u_long)lrp->numobjs);
-	printf("%s:%lu\t%s:%lu\t%s:%lu\n%s:%lu\t%s:%lu\t%s:%lu\n",
-	    "size       ", (u_long)lrp->hdr.size,
-	    "nlockers   ", (u_long)lrp->nlockers,
-	    "hash_off   ", (u_long)lrp->hash_off,
-	    "increment  ", (u_long)lrp->increment,
-	    "mem_off    ", (u_long)lrp->mem_off,
-	    "mem_bytes  ", (u_long)lrp->mem_bytes);
-#ifndef HAVE_SPINLOCKS
-	printf("Mutex: off %lu", (u_long)lrp->hdr.lock.off);
-#endif
-	printf(" waits %lu nowaits %lu",
-	    (u_long)lrp->hdr.lock.mutex_set_wait,
-	    (u_long)lrp->hdr.lock.mutex_set_nowait);
-	printf("\n%s:%lu\t%s:%lu\t%s:%lu\t%s:%lu\n",
-	    "nconflicts ", (u_long)lrp->nconflicts,
-	    "nrequests  ", (u_long)lrp->nrequests,
-	    "nreleases  ", (u_long)lrp->nreleases,
-	    "ndeadlocks ", (u_long)lrp->ndeadlocks);
-	printf("need_dd    %lu\n", (u_long)lrp->need_dd);
-	if (flags & LOCK_DEBUG_CONF) {
-		printf("\nConflict matrix\n");
-
-		for (i = 0; i < lrp->nmodes; i++) {
-			for (j = 0; j < lrp->nmodes; j++)
-				printf("%lu\t",
-				    (u_long)lt->conflicts[i * lrp->nmodes + j]);
-			printf("\n");
-		}
-	}
-
-	for (i = 0; i < lrp->table_size; i++) {
-		op = SH_TAILQ_FIRST(&lt->hashtab[i], __db_lockobj);
-		if (op != NULL && flags & LOCK_DEBUG_BUCKET)
-			printf("Bucket %lu:\n", (unsigned long)i);
-		while (op != NULL) {
-			if (op->type == DB_LOCK_LOCKER &&
-			    flags & LOCK_DEBUG_LOCKERS)
-				__lock_dump_locker(lt, op);
-			else if (flags & LOCK_DEBUG_OBJECTS &&
-			    op->type == DB_LOCK_OBJTYPE)
-				__lock_dump_object(lt, op);
-			op = SH_TAILQ_NEXT(op, links, __db_lockobj);
-		}
-	}
-
-	if (flags & LOCK_DEBUG_LOCK) {
-		printf("\nLock Free List\n");
-		for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
-		    lp != NULL;
-		    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
-			printf("0x%x: %lu\t%lu\t%lu\t0x%x\n", (u_int)lp,
-			    (u_long)lp->holder, (u_long)lp->mode,
-			    (u_long)lp->status, (u_int)lp->obj);
-		}
-	}
-
-	if (flags & LOCK_DEBUG_LOCK) {
-		printf("\nObject Free List\n");
-		for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
-		    op != NULL;
-		    op = SH_TAILQ_NEXT(op, links, __db_lockobj))
-			printf("0x%x\n", (u_int)op);
-	}
-
-	if (flags & LOCK_DEBUG_MEM) {
-		printf("\nMemory Free List\n");
-		__db_shalloc_dump(stdout, lt->mem);
-	}
-}
-
-static void
-__lock_dump_locker(lt, op)
-	DB_LOCKTAB *lt;
-	DB_LOCKOBJ *op;
-{
-	struct __db_lock *lp;
-	u_int32_t locker;
-	void *ptr;
-
-	ptr = SH_DBT_PTR(&op->lockobj);
-	memcpy(&locker, ptr, sizeof(u_int32_t));
-	printf("L %lx", (u_long)locker);
-
-	lp = SH_LIST_FIRST(&op->heldby, __db_lock);
-	if (lp == NULL) {
-		printf("\n");
-		return;
-	}
-	for (; lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock))
-		__lock_printlock(lt, lp, 0);
-}
-
-static void
-__lock_dump_object(lt, op)
-	DB_LOCKTAB *lt;
-	DB_LOCKOBJ *op;
-{
-	struct __db_lock *lp;
-	u_int32_t j;
-	char *ptr;
-
-	ptr = SH_DBT_PTR(&op->lockobj);
-	for (j = 0; j < op->lockobj.size; ptr++, j++)
-		printf("%c", (int)*ptr);
-	printf("\n");
-
-	printf("H:");
-	for (lp =
-	    SH_TAILQ_FIRST(&op->holders, __db_lock);
-	    lp != NULL;
-	    lp = SH_TAILQ_NEXT(lp, links, __db_lock))
-		__lock_printlock(lt, lp, 0);
-	lp = SH_TAILQ_FIRST(&op->waiters, __db_lock);
-	if (lp != NULL) {
-		printf("\nW:");
-		for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock))
-			__lock_printlock(lt, lp, 0);
-	}
-}
-
-/*
  * __lock_is_locked --
  *
  * PUBLIC: int __lock_is_locked
@@ -1136,7 +565,12 @@ __lock_is_locked(lt, locker, dbt, mode)
 	return (0);
 }
 
-static void
+/*
+ * __lock_printlock --
+ *
+ * PUBLIC: void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int));
+ */
+void
 __lock_printlock(lt, lp, ispgno)
 	DB_LOCKTAB *lt;
 	struct __db_lock *lp;
@@ -1213,39 +647,6 @@ __lock_printlock(lt, lp, ispgno)
 		printf("\n");
 	}
 }
-#endif
-
-static int
-__lock_count_locks(lrp)
-	DB_LOCKREGION *lrp;
-{
-	struct __db_lock *newl;
-	int count;
-
-	count = 0;
-	for (newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
-	    newl != NULL;
-	    newl = SH_TAILQ_NEXT(newl, links, __db_lock))
-		count++;
-
-	return (count);
-}
-
-static int
-__lock_count_objs(lrp)
-	DB_LOCKREGION *lrp;
-{
-	DB_LOCKOBJ *obj;
-	int count;
-
-	count = 0;
-	for (obj = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
-	    obj != NULL;
-	    obj = SH_TAILQ_NEXT(obj, links, __db_lockobj))
-		count++;
-
-	return (count);
-}
 
 /*
  * PUBLIC: int __lock_getobj  __P((DB_LOCKTAB *,
@@ -1354,19 +755,7 @@ __lock_remove_waiter(lt, sh_obj, lockp, status)
 	lockp->status = status;
 
 	/* Wake whoever is waiting on this lock. */
-	(void)__db_mutex_unlock(&lockp->mutex, lt->fd);
-}
-
-static void
-__lock_freeobj(lt, obj)
-	DB_LOCKTAB *lt;
-	DB_LOCKOBJ *obj;
-{
-	HASHREMOVE_EL(lt->hashtab,
-	    __db_lockobj, links, obj, lt->region->table_size, __lock_lhash);
-	if (obj->lockobj.size > sizeof(obj->objdata))
-		__db_shalloc_free(lt->mem, SH_DBT_PTR(&obj->lockobj));
-	SH_TAILQ_INSERT_HEAD(&lt->region->free_objs, obj, links, __db_lockobj);
+	(void)__db_mutex_unlock(&lockp->mutex, lt->reginfo.fd);
 }
 
 static void
@@ -1384,17 +773,18 @@ __lock_checklocker(lt, lockp, do_remove)
 	if (__lock_getobj(lt, lockp->holder, NULL, DB_LOCK_LOCKER, &sh_locker)
 	    == 0 && SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL) {
 		__lock_freeobj(lt, sh_locker);
-		lt->region->nlockers--;
+		    lt->region->nlockers--;
 	}
 }
 
 static void
-__lock_reset_region(lt)
+__lock_freeobj(lt, obj)
 	DB_LOCKTAB *lt;
+	DB_LOCKOBJ *obj;
 {
-	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
-	lt->hashtab =
-	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
-	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
-	lt->reg_size = lt->region->hdr.size;
+	HASHREMOVE_EL(lt->hashtab,
+	    __db_lockobj, links, obj, lt->region->table_size, __lock_lhash);
+	if (obj->lockobj.size > sizeof(obj->objdata))
+		__db_shalloc_free(lt->mem, SH_DBT_PTR(&obj->lockobj));
+	SH_TAILQ_INSERT_HEAD(&lt->region->free_objs, obj, links, __db_lockobj);
 }
diff --git a/db2/lock/lock_conflict.c b/db2/lock/lock_conflict.c
index ff0287f07e..870aa0dc17 100644
--- a/db2/lock/lock_conflict.c
+++ b/db2/lock/lock_conflict.c
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *	Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_conflict.c	10.2 (Sleepycat) 6/21/97";
+static const char sccsid[] = "@(#)lock_conflict.c	10.3 (Sleepycat) 4/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
diff --git a/db2/lock/lock_deadlock.c b/db2/lock/lock_deadlock.c
index 93c438ca36..4de492944e 100644
--- a/db2/lock/lock_deadlock.c
+++ b/db2/lock/lock_deadlock.c
@@ -1,25 +1,21 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *	Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1997\n\
-	Sleepycat Software Inc.  All rights reserved.\n";
-static const char sccsid[] = "@(#)lock_deadlock.c	10.26 (Sleepycat) 11/25/97";
-#endif
+static const char sccsid[] = "@(#)lock_deadlock.c	10.32 (Sleepycat) 4/26/98";
+#endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
 #include <string.h>
-#include <stdlib.h>
 #endif
 
 #include "db_int.h"
@@ -59,14 +55,14 @@ static int  __dd_build
 static u_int32_t
 	   *__dd_find __P((u_int32_t *, locker_info *, u_int32_t));
 
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
 static void __dd_debug __P((DB_ENV *, locker_info *, u_int32_t *, u_int32_t));
 #endif
 
 int
 lock_detect(lt, flags, atype)
 	DB_LOCKTAB *lt;
-	int flags, atype;
+	u_int32_t flags, atype;
 {
 	DB_ENV *dbenv;
 	locker_info *idmap;
@@ -96,7 +92,7 @@ lock_detect(lt, flags, atype)
 
 	if (nlockers == 0)
 		return (0);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
 	if (dbenv->db_verbose != 0)
 		__dd_debug(dbenv, idmap, bitmap, nlockers);
 #endif
@@ -202,7 +198,7 @@ __dd_build(dbenv, bmp, nlockers, idmap)
 	u_int8_t *pptr;
 	locker_info *id_array;
 	u_int32_t *bitmap, count, *entryp, i, id, nentries, *tmpmap;
-	int is_first, ret;
+	int is_first;
 
 	lt = dbenv->lk_info;
 
@@ -322,8 +318,8 @@ retry:	count = lt->region->nlockers;
 			    lp != NULL;
 			    is_first = 0,
 			    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
-				if ((ret = __lock_getobj(lt, lp->holder,
-				    NULL, DB_LOCK_LOCKER, &lockerp)) != 0) {
+				if (__lock_getobj(lt, lp->holder,
+				    NULL, DB_LOCK_LOCKER, &lockerp) != 0) {
 					__db_err(dbenv,
 					    "warning unable to find object");
 					continue;
@@ -357,8 +353,8 @@ retry:	count = lt->region->nlockers;
 	for (id = 0; id < count; id++) {
 		if (!id_array[id].valid)
 			continue;
-		if ((ret = __lock_getobj(lt,
-		    id_array[id].id, NULL, DB_LOCK_LOCKER, &lockerp)) != 0) {
+		if (__lock_getobj(lt,
+		    id_array[id].id, NULL, DB_LOCK_LOCKER, &lockerp) != 0) {
 			__db_err(dbenv,
 			    "No locks for locker %lu", (u_long)id_array[id].id);
 			continue;
@@ -448,7 +444,7 @@ __dd_abort(dbenv, info)
 	SH_LIST_REMOVE(lockp, locker_links, __db_lock);
 	sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
 	SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);
-        (void)__db_mutex_unlock(&lockp->mutex, lt->fd);
+        (void)__db_mutex_unlock(&lockp->mutex, lt->reginfo.fd);
 
 	ret = 0;
 
@@ -456,7 +452,7 @@ out:	UNLOCK_LOCKREGION(lt);
 	return (ret);
 }
 
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
 static void
 __dd_debug(dbenv, idmap, bitmap, nlockers)
 	DB_ENV *dbenv;
diff --git a/db2/lock/lock_region.c b/db2/lock/lock_region.c
new file mode 100644
index 0000000000..b597560744
--- /dev/null
+++ b/db2/lock/lock_region.c
@@ -0,0 +1,726 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998
+ *	Sleepycat Software.  All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)lock_region.c	10.15 (Sleepycat) 6/2/98";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "shqueue.h"
+#include "db_shash.h"
+#include "lock.h"
+#include "common_ext.h"
+
+static u_int32_t __lock_count_locks __P((DB_LOCKREGION *));
+static u_int32_t __lock_count_objs __P((DB_LOCKREGION *));
+static void	 __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
+static void	 __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
+static const char *__lock_dump_status __P((db_status_t));
+static void	 __lock_reset_region __P((DB_LOCKTAB *));
+static int	 __lock_tabinit __P((DB_ENV *, DB_LOCKREGION *));
+
+int
+lock_open(path, flags, mode, dbenv, ltp)
+	const char *path;
+	u_int32_t flags;
+	int mode;
+	DB_ENV *dbenv;
+	DB_LOCKTAB **ltp;
+{
+	DB_LOCKTAB *lt;
+	u_int32_t lock_modes, maxlocks, regflags;
+	int ret;
+
+	/* Validate arguments. */
+#ifdef HAVE_SPINLOCKS
+#define	OKFLAGS	(DB_CREATE | DB_THREAD)
+#else
+#define	OKFLAGS	(DB_CREATE)
+#endif
+	if ((ret = __db_fchk(dbenv, "lock_open", flags, OKFLAGS)) != 0)
+		return (ret);
+
+	/* Create the lock table structure. */
+	if ((lt = (DB_LOCKTAB *)__db_calloc(1, sizeof(DB_LOCKTAB))) == NULL) {
+		__db_err(dbenv, "%s", strerror(ENOMEM));
+		return (ENOMEM);
+	}
+	lt->dbenv = dbenv;
+
+	/* Grab the values that we need to compute the region size. */
+	lock_modes = DB_LOCK_RW_N;
+	maxlocks = DB_LOCK_DEFAULT_N;
+	regflags = REGION_SIZEDEF;
+	if (dbenv != NULL) {
+		if (dbenv->lk_modes != 0) {
+			lock_modes = dbenv->lk_modes;
+			regflags = 0;
+		}
+		if (dbenv->lk_max != 0) {
+			maxlocks = dbenv->lk_max;
+			regflags = 0;
+		}
+	}
+
+	/* Join/create the lock region. */
+	lt->reginfo.dbenv = dbenv;
+	lt->reginfo.appname = DB_APP_NONE;
+	if (path == NULL)
+		lt->reginfo.path = NULL;
+	else
+		if ((lt->reginfo.path = (char *)__db_strdup(path)) == NULL)
+			goto err;
+	lt->reginfo.file = DB_DEFAULT_LOCK_FILE;
+	lt->reginfo.mode = mode;
+	lt->reginfo.size =
+	    LOCK_REGION_SIZE(lock_modes, maxlocks, __db_tablesize(maxlocks));
+	lt->reginfo.dbflags = flags;
+	lt->reginfo.addr = NULL;
+	lt->reginfo.fd = -1;
+	lt->reginfo.flags = regflags;
+
+	if ((ret = __db_rattach(&lt->reginfo)) != 0)
+		goto err;
+
+	/* Now set up the pointer to the region. */
+	lt->region = lt->reginfo.addr;
+
+	/* Initialize the region if we created it. */
+	if (F_ISSET(&lt->reginfo, REGION_CREATED)) {
+		lt->region->maxlocks = maxlocks;
+		lt->region->nmodes = lock_modes;
+		if ((ret = __lock_tabinit(dbenv, lt->region)) != 0)
+			goto err;
+	} else {
+		/* Check for an unexpected region. */
+		if (lt->region->magic != DB_LOCKMAGIC) {
+			__db_err(dbenv,
+			    "lock_open: %s: bad magic number", path);
+			ret = EINVAL;
+			goto err;
+		}
+	}
+
+	/* Check for automatic deadlock detection. */
+	if (dbenv != NULL && dbenv->lk_detect != DB_LOCK_NORUN) {
+		if (lt->region->detect != DB_LOCK_NORUN &&
+		    dbenv->lk_detect != DB_LOCK_DEFAULT &&
+		    lt->region->detect != dbenv->lk_detect) {
+			__db_err(dbenv,
+		    "lock_open: incompatible deadlock detector mode");
+			ret = EINVAL;
+			goto err;
+		}
+		if (lt->region->detect == DB_LOCK_NORUN)
+			lt->region->detect = dbenv->lk_detect;
+	}
+
+	/* Set up remaining pointers into region. */
+	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
+	lt->hashtab =
+	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
+	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
+
+	UNLOCK_LOCKREGION(lt);
+	*ltp = lt;
+	return (0);
+
+err:	if (lt->reginfo.addr != NULL) {
+		UNLOCK_LOCKREGION(lt);
+		(void)__db_rdetach(&lt->reginfo);
+		if (F_ISSET(&lt->reginfo, REGION_CREATED))
+			(void)lock_unlink(path, 1, dbenv);
+	}
+
+	if (lt->reginfo.path != NULL)
+		FREES(lt->reginfo.path);
+	FREE(lt, sizeof(*lt));
+	return (ret);
+}
+
+/*
+ * __lock_tabinit --
+ *	Initialize the lock region.
+ */
+static int
+__lock_tabinit(dbenv, lrp)
+	DB_ENV *dbenv;
+	DB_LOCKREGION *lrp;
+{
+	struct __db_lock *lp;
+	struct lock_header *tq_head;
+	struct obj_header *obj_head;
+	DB_LOCKOBJ *op;
+	u_int32_t i, nelements;
+	const u_int8_t *conflicts;
+	u_int8_t *curaddr;
+
+	conflicts = dbenv == NULL || dbenv->lk_conflicts == NULL ?
+	    db_rw_conflicts : dbenv->lk_conflicts;
+
+	lrp->table_size = __db_tablesize(lrp->maxlocks);
+	lrp->magic = DB_LOCKMAGIC;
+	lrp->version = DB_LOCKVERSION;
+	lrp->id = 0;
+	/*
+	 * These fields (lrp->maxlocks, lrp->nmodes) are initialized
+	 * in the caller, since we had to grab those values to size
+	 * the region.
+	 */
+	lrp->need_dd = 0;
+	lrp->detect = DB_LOCK_NORUN;
+	lrp->numobjs = lrp->maxlocks;
+	lrp->nlockers = 0;
+	lrp->mem_bytes = ALIGN(STRING_SIZE(lrp->maxlocks), sizeof(size_t));
+	lrp->increment = lrp->hdr.size / 2;
+	lrp->nconflicts = 0;
+	lrp->nrequests = 0;
+	lrp->nreleases = 0;
+	lrp->ndeadlocks = 0;
+
+	/*
+	 * As we write the region, we've got to maintain the alignment
+	 * for the structures that follow each chunk.  This information
+	 * ends up being encapsulated both in here as well as in the
+	 * lock.h file for the XXX_SIZE macros.
+	 */
+	/* Initialize conflict matrix. */
+	curaddr = (u_int8_t *)lrp + sizeof(DB_LOCKREGION);
+	memcpy(curaddr, conflicts, lrp->nmodes * lrp->nmodes);
+	curaddr += lrp->nmodes * lrp->nmodes;
+
+	/*
+	 * Initialize hash table.
+	 */
+	curaddr = (u_int8_t *)ALIGNP(curaddr, LOCK_HASH_ALIGN);
+	lrp->hash_off = curaddr - (u_int8_t *)lrp;
+	nelements = lrp->table_size;
+	__db_hashinit(curaddr, nelements);
+	curaddr += nelements * sizeof(DB_HASHTAB);
+
+	/*
+	 * Initialize locks onto a free list. Since locks contains mutexes,
+	 * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT
+	 * boundary.
+	 */
+	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
+	tq_head = &lrp->free_locks;
+	SH_TAILQ_INIT(tq_head);
+
+	for (i = 0; i++ < lrp->maxlocks;
+	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
+		lp = (struct __db_lock *)curaddr;
+		lp->status = DB_LSTAT_FREE;
+		SH_TAILQ_INSERT_HEAD(tq_head, lp, links, __db_lock);
+	}
+
+	/* Initialize objects onto a free list.  */
+	obj_head = &lrp->free_objs;
+	SH_TAILQ_INIT(obj_head);
+
+	for (i = 0; i++ < lrp->maxlocks; curaddr += sizeof(DB_LOCKOBJ)) {
+		op = (DB_LOCKOBJ *)curaddr;
+		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
+	}
+
+	/*
+	 * Initialize the string space; as for all shared memory allocation
+	 * regions, this requires size_t alignment, since we store the
+	 * lengths of malloc'd areas in the area.
+	 */
+	curaddr = (u_int8_t *)ALIGNP(curaddr, sizeof(size_t));
+	lrp->mem_off = curaddr - (u_int8_t *)lrp;
+	__db_shalloc_init(curaddr, lrp->mem_bytes);
+	return (0);
+}
+
+int
+lock_close(lt)
+	DB_LOCKTAB *lt;
+{
+	int ret;
+
+	if ((ret = __db_rdetach(&lt->reginfo)) != 0)
+		return (ret);
+
+	if (lt->reginfo.path != NULL)
+		FREES(lt->reginfo.path);
+	FREE(lt, sizeof(*lt));
+
+	return (0);
+}
+
+int
+lock_unlink(path, force, dbenv)
+	const char *path;
+	int force;
+	DB_ENV *dbenv;
+{
+	REGINFO reginfo;
+	int ret;
+
+	memset(&reginfo, 0, sizeof(reginfo));
+	reginfo.dbenv = dbenv;
+	reginfo.appname = DB_APP_NONE;
+	if (path != NULL && (reginfo.path = (char *)__db_strdup(path)) == NULL)
+		return (ENOMEM);
+	reginfo.file = DB_DEFAULT_LOCK_FILE;
+	ret = __db_runlink(&reginfo, force);
+	if (reginfo.path != NULL)
+		FREES(reginfo.path);
+	return (ret);
+}
+
+/*
+ * __lock_validate_region --
+ *	Called at every interface to verify if the region has changed size,
+ *	and if so, to remap the region in and reset the process' pointers.
+ *
+ * PUBLIC: int __lock_validate_region __P((DB_LOCKTAB *));
+ */
+int
+__lock_validate_region(lt)
+	DB_LOCKTAB *lt;
+{
+	int ret;
+
+	if (lt->reginfo.size == lt->region->hdr.size)
+		return (0);
+
+	/* Detach/reattach the region. */
+	if ((ret = __db_rreattach(&lt->reginfo, lt->region->hdr.size)) != 0)
+		return (ret);
+
+	/* Reset region information. */
+	lt->region = lt->reginfo.addr;
+	__lock_reset_region(lt);
+
+	return (0);
+}
+
+/*
+ * __lock_grow_region --
+ *	We have run out of space; time to grow the region.
+ *
+ * PUBLIC: int __lock_grow_region __P((DB_LOCKTAB *, int, size_t));
+ */
+int
+__lock_grow_region(lt, which, howmuch)
+	DB_LOCKTAB *lt;
+	int which;
+	size_t howmuch;
+{
+	struct __db_lock *newl;
+	struct lock_header *lock_head;
+	struct obj_header *obj_head;
+	DB_LOCKOBJ *op;
+	DB_LOCKREGION *lrp;
+	float lock_ratio, obj_ratio;
+	size_t incr, oldsize, used, usedmem;
+	u_int32_t i, newlocks, newmem, newobjs, usedlocks, usedobjs;
+	u_int8_t *curaddr;
+	int ret;
+
+	lrp = lt->region;
+	oldsize = lrp->hdr.size;
+	incr = lrp->increment;
+
+	/* Figure out how much of each sort of space we have. */
+	usedmem = lrp->mem_bytes - __db_shalloc_count(lt->mem);
+	usedobjs = lrp->numobjs - __lock_count_objs(lrp);
+	usedlocks = lrp->maxlocks - __lock_count_locks(lrp);
+
+	/*
+	 * Figure out what fraction of the used space belongs to each
+	 * different type of "thing" in the region.  Then partition the
+	 * new space up according to this ratio.
+	 */
+	used = usedmem +
+	    usedlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) +
+	    usedobjs * sizeof(DB_LOCKOBJ);
+
+	lock_ratio = usedlocks *
+	    ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) / (float)used;
+	obj_ratio = usedobjs * sizeof(DB_LOCKOBJ) / (float)used;
+
+	newlocks = (u_int32_t)(lock_ratio *
+	    incr / ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
+	newobjs = (u_int32_t)(obj_ratio * incr / sizeof(DB_LOCKOBJ));
+	newmem = incr -
+	    (newobjs * sizeof(DB_LOCKOBJ) +
+	    newlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
+
+	/*
+	 * Make sure we allocate enough memory for the object being
+	 * requested.
+	 */
+	switch (which) {
+	case DB_LOCK_LOCK:
+		if (newlocks == 0) {
+			newlocks = 10;
+			incr += newlocks * sizeof(struct __db_lock);
+		}
+		break;
+	case DB_LOCK_OBJ:
+		if (newobjs == 0) {
+			newobjs = 10;
+			incr += newobjs * sizeof(DB_LOCKOBJ);
+		}
+		break;
+	case DB_LOCK_MEM:
+		if (newmem < howmuch * 2) {
+			incr += howmuch * 2 - newmem;
+			newmem = howmuch * 2;
+		}
+		break;
+	}
+
+	newmem += ALIGN(incr, sizeof(size_t)) - incr;
+	incr = ALIGN(incr, sizeof(size_t));
+
+	/*
+	 * Since we are going to be allocating locks at the beginning of the
+	 * new chunk, we need to make sure that the chunk is MUTEX_ALIGNMENT
+	 * aligned.  We did not guarantee this when we created the region, so
+	 * we may need to pad the old region by extra bytes to ensure this
+	 * alignment.
+	 */
+	incr += ALIGN(oldsize, MUTEX_ALIGNMENT) - oldsize;
+
+	__db_err(lt->dbenv,
+	    "Growing lock region: %lu locks %lu objs %lu bytes",
+	    (u_long)newlocks, (u_long)newobjs, (u_long)newmem);
+
+	if ((ret = __db_rgrow(&lt->reginfo, oldsize + incr)) != 0)
+		return (ret);
+	lt->region = lt->reginfo.addr;
+	__lock_reset_region(lt);
+
+	/* Update region parameters. */
+	lrp = lt->region;
+	lrp->increment = incr << 1;
+	lrp->maxlocks += newlocks;
+	lrp->numobjs += newobjs;
+	lrp->mem_bytes += newmem;
+
+	curaddr = (u_int8_t *)lrp + oldsize;
+	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
+
+	/* Put new locks onto the free list. */
+	lock_head = &lrp->free_locks;
+	for (i = 0; i++ < newlocks;
+	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
+		newl = (struct __db_lock *)curaddr;
+		SH_TAILQ_INSERT_HEAD(lock_head, newl, links, __db_lock);
+	}
+
+	/* Put new objects onto the free list.  */
+	obj_head = &lrp->free_objs;
+	for (i = 0; i++ < newobjs; curaddr += sizeof(DB_LOCKOBJ)) {
+		op = (DB_LOCKOBJ *)curaddr;
+		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
+	}
+
+	*((size_t *)curaddr) = newmem - sizeof(size_t);
+	curaddr += sizeof(size_t);
+	__db_shalloc_free(lt->mem, curaddr);
+
+	return (0);
+}
+
+static void
+__lock_reset_region(lt)
+	DB_LOCKTAB *lt;
+{
+	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
+	lt->hashtab =
+	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
+	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
+}
+
+/*
+ * lock_stat --
+ *	Return LOCK statistics.
+ */
+int
+lock_stat(lt, gspp, db_malloc)
+	DB_LOCKTAB *lt;
+	DB_LOCK_STAT **gspp;
+	void *(*db_malloc) __P((size_t));
+{
+	DB_LOCKREGION *rp;
+
+	*gspp = NULL;
+
+	if ((*gspp = db_malloc == NULL ?
+	    (DB_LOCK_STAT *)__db_malloc(sizeof(**gspp)) :
+	    (DB_LOCK_STAT *)db_malloc(sizeof(**gspp))) == NULL)
+		return (ENOMEM);
+
+	/* Copy out the global statistics. */
+	LOCK_LOCKREGION(lt);
+
+	rp = lt->region;
+	(*gspp)->st_magic = rp->magic;
+	(*gspp)->st_version = rp->version;
+	(*gspp)->st_maxlocks = rp->maxlocks;
+	(*gspp)->st_nmodes = rp->nmodes;
+	(*gspp)->st_numobjs = rp->numobjs;
+	(*gspp)->st_nlockers = rp->nlockers;
+	(*gspp)->st_nconflicts = rp->nconflicts;
+	(*gspp)->st_nrequests = rp->nrequests;
+	(*gspp)->st_nreleases = rp->nreleases;
+	(*gspp)->st_ndeadlocks = rp->ndeadlocks;
+	(*gspp)->st_region_nowait = rp->hdr.lock.mutex_set_nowait;
+	(*gspp)->st_region_wait = rp->hdr.lock.mutex_set_wait;
+	(*gspp)->st_refcnt = rp->hdr.refcnt;
+	(*gspp)->st_regsize = rp->hdr.size;
+
+	UNLOCK_LOCKREGION(lt);
+
+	return (0);
+}
+
+static u_int32_t
+__lock_count_locks(lrp)
+	DB_LOCKREGION *lrp;
+{
+	struct __db_lock *newl;
+	u_int32_t count;
+
+	count = 0;
+	for (newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
+	    newl != NULL;
+	    newl = SH_TAILQ_NEXT(newl, links, __db_lock))
+		count++;
+
+	return (count);
+}
+
+static u_int32_t
+__lock_count_objs(lrp)
+	DB_LOCKREGION *lrp;
+{
+	DB_LOCKOBJ *obj;
+	u_int32_t count;
+
+	count = 0;
+	for (obj = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
+	    obj != NULL;
+	    obj = SH_TAILQ_NEXT(obj, links, __db_lockobj))
+		count++;
+
+	return (count);
+}
+
+#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_LOCKTAB *, char *, FILE *));
+ */
+void
+__lock_dump_region(lt, area, fp)
+	DB_LOCKTAB *lt;
+	char *area;
+	FILE *fp;
+{
+	struct __db_lock *lp;
+	DB_LOCKOBJ *op;
+	DB_LOCKREGION *lrp;
+	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;
+		}
+
+	lrp = lt->region;
+
+	fprintf(fp, "%s\nLock region parameters\n", DB_LINE);
+	fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu\n%s: %lu, %s: %lu\n",
+	    "table size", (u_long)lrp->table_size,
+	    "hash_off", (u_long)lrp->hash_off,
+	    "increment", (u_long)lrp->increment,
+	    "mem_off", (u_long)lrp->mem_off,
+	    "mem_bytes", (u_long)lrp->mem_bytes,
+	    "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 | LOCK_DUMP_OBJECTS)) {
+		fprintf(fp, "%s\nLock hash buckets\n", DB_LINE);
+		for (i = 0; i < lrp->table_size; i++) {
+			label = 1;
+			for (op = SH_TAILQ_FIRST(&lt->hashtab[i], __db_lockobj);
+			    op != NULL;
+			    op = SH_TAILQ_NEXT(op, links, __db_lockobj)) {
+				if (LF_ISSET(LOCK_DUMP_LOCKERS) &&
+				    op->type == DB_LOCK_LOCKER) {
+					if (label) {
+						fprintf(fp,
+						    "Bucket %lu:\n", (u_long)i);
+						label = 0;
+					}
+					__lock_dump_locker(lt, op, fp);
+				}
+				if (LF_ISSET(LOCK_DUMP_OBJECTS) &&
+				    op->type == DB_LOCK_OBJTYPE) {
+					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%x: %lu\t%lu\t%s\t0x%x\n", (u_int)lp,
+			    (u_long)lp->holder, (u_long)lp->mode,
+			    __lock_dump_status(lp->status), (u_int)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%x\n", (u_int)op);
+	}
+
+	if (LF_ISSET(LOCK_DUMP_MEM))
+		__db_shalloc_dump(lt->mem, fp);
+}
+
+static void
+__lock_dump_locker(lt, op, fp)
+	DB_LOCKTAB *lt;
+	DB_LOCKOBJ *op;
+	FILE *fp;
+{
+	struct __db_lock *lp;
+	u_int32_t locker;
+	void *ptr;
+
+	ptr = SH_DBT_PTR(&op->lockobj);
+	memcpy(&locker, ptr, sizeof(u_int32_t));
+	fprintf(fp, "L %lx", (u_long)locker);
+
+	lp = SH_LIST_FIRST(&op->heldby, __db_lock);
+	if (lp == NULL) {
+		fprintf(fp, "\n");
+		return;
+	}
+	for (; lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock))
+		__lock_printlock(lt, lp, 0);
+}
+
+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, 0);
+	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, 0);
+	}
+}
+
+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");
+}
diff --git a/db2/lock/lock_util.c b/db2/lock/lock_util.c
index 6c1e30f27c..7274a50422 100644
--- a/db2/lock/lock_util.c
+++ b/db2/lock/lock_util.c
@@ -1,25 +1,20 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *	Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_util.c	10.5 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)lock_util.c	10.9 (Sleepycat) 4/26/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #endif
 
 #include "db_int.h"
@@ -30,11 +25,13 @@ static const char sccsid[] = "@(#)lock_util.c	10.5 (Sleepycat) 1/8/98";
 #include "lock.h"
 
 /*
- * This function is used to compare a DBT that is about to be entered
- * into a hash table with an object already in the hash table.  Note
- * that it just returns true on equal and 0 on not-equal.  Therefore this
- * cannot be used as a sort function; its purpose is to be used as a
- * hash comparison function.
+ * __lock_cmp --
+ *	This function is used to compare a DBT that is about to be entered
+ *	into a hash table with an object already in the hash table.  Note
+ *	that it just returns true on equal and 0 on not-equal.  Therefore
+ *	this function cannot be used as a sort function; its purpose is to
+ *	be used as a hash comparison function.
+ *
  * PUBLIC: int __lock_cmp __P((const DBT *, DB_LOCKOBJ *));
  */
 int
@@ -46,6 +43,7 @@ __lock_cmp(dbt, lock_obj)
 
 	if (lock_obj->type != DB_LOCK_OBJTYPE)
 		return (0);
+
 	obj_data = SH_DBT_PTR(&lock_obj->lockobj);
 	return (dbt->size == lock_obj->lockobj.size &&
 		memcmp(dbt->data, obj_data, dbt->size) == 0);
@@ -69,35 +67,86 @@ __lock_locker_cmp(locker, lock_obj)
 }
 
 /*
- * PUBLIC: int __lock_ohash __P((const DBT *));
+ * The next two functions are the hash functions used to store objects in the
+ * lock hash table.  They are hashing the same items, but one (__lock_ohash)
+ * takes a DBT (used for hashing a parameter passed from the user) and the
+ * other (__lock_lhash) takes a DB_LOCKOBJ (used for hashing something that is
+ * already in the lock manager).  In both cases, we have a special check to
+ * fast path the case where we think we are doing a hash on a DB page/fileid
+ * pair.  If the size is right, then we do the fast hash.
+ *
+ * We know that DB uses struct __db_ilocks for its lock objects.  The first
+ * four bytes are the 4-byte page number and the next DB_FILE_ID_LEN bytes
+ * are a unique file id, where the first 4 bytes on UNIX systems are the file
+ * inode number, and the first 4 bytes on Windows systems are the FileIndexLow
+ * bytes.  So, we use the XOR of the page number and the first four bytes of
+ * the file id to produce a 32-bit hash value.
+ *
+ * We have no particular reason to believe that this algorithm will produce
+ * a good hash, but we want a fast hash more than we want a good one, when
+ * we're coming through this code path.
  */
-int
-__lock_ohash(dbt)
-	const DBT *dbt;
-{
-	return (__ham_func5(dbt->data, dbt->size));
+#define FAST_HASH(P) {			\
+	u_int32_t __h;			\
+	u_int8_t *__cp, *__hp;		\
+	__hp = (u_int8_t *)&__h;	\
+	__cp = (u_int8_t *)(P);		\
+	__hp[0] = __cp[0] ^ __cp[4];	\
+	__hp[1] = __cp[1] ^ __cp[5];	\
+	__hp[2] = __cp[2] ^ __cp[6];	\
+	__hp[3] = __cp[3] ^ __cp[7];	\
+	return (__h);			\
 }
 
 /*
- * PUBLIC: u_int32_t __lock_locker_hash __P((u_int32_t));
+ * __lock_ohash --
+ *
+ * PUBLIC: u_int32_t __lock_ohash __P((const DBT *));
  */
 u_int32_t
-__lock_locker_hash(locker)
-	u_int32_t locker;
+__lock_ohash(dbt)
+	const DBT *dbt;
 {
-	return (__ham_func5(&locker, sizeof(locker)));
+	if (dbt->size == sizeof(struct __db_ilock))
+		FAST_HASH(dbt->data);
+
+	return (__ham_func5(dbt->data, dbt->size));
 }
 
 /*
+ * __lock_lhash --
+ *
  * PUBLIC: u_int32_t __lock_lhash __P((DB_LOCKOBJ *));
  */
 u_int32_t
 __lock_lhash(lock_obj)
 	DB_LOCKOBJ *lock_obj;
 {
+	u_int32_t tmp;
 	void *obj_data;
 
 	obj_data = SH_DBT_PTR(&lock_obj->lockobj);
+	if (lock_obj->type == DB_LOCK_LOCKER) {
+		memcpy(&tmp, obj_data, sizeof(u_int32_t));
+		return (tmp);
+	}
+
+	if (lock_obj->lockobj.size == sizeof(struct __db_ilock))
+		FAST_HASH(obj_data);
+
 	return (__ham_func5(obj_data, lock_obj->lockobj.size));
 }
 
+/*
+ * __lock_locker_hash --
+ *	Hash function for entering lockers into the hash table.  Since these
+ *	are simply 32-bit unsigned integers, just return the locker value.
+ *
+ * PUBLIC: u_int32_t __lock_locker_hash __P((u_int32_t));
+ */
+u_int32_t
+__lock_locker_hash(locker)
+	u_int32_t locker;
+{
+	return (locker);
+}