about summary refs log tree commit diff
path: root/db2/lock
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-06-13 13:36:34 +0000
committerUlrich Drepper <drepper@redhat.com>1999-06-13 13:36:34 +0000
commitec239360d13518a13f572b635d036c7d10028010 (patch)
treebdb5111363f45d2107849c2456b575d72779174c /db2/lock
parentfc3703521650a9b6db910a50c4fc0f410496e134 (diff)
downloadglibc-ec239360d13518a13f572b635d036c7d10028010.tar.gz
glibc-ec239360d13518a13f572b635d036c7d10028010.tar.xz
glibc-ec239360d13518a13f572b635d036c7d10028010.zip
Update.
	* db2/Makefile (distribute): Remove files which do not exist
	anymore.
Diffstat (limited to 'db2/lock')
-rw-r--r--db2/lock/lock.c386
-rw-r--r--db2/lock/lock_conflict.c8
-rw-r--r--db2/lock/lock_deadlock.c76
-rw-r--r--db2/lock/lock_region.c59
-rw-r--r--db2/lock/lock_util.c8
5 files changed, 404 insertions, 133 deletions
diff --git a/db2/lock/lock.c b/db2/lock/lock.c
index 3d20e0d65b..4cf1d9ecca 100644
--- a/db2/lock/lock.c
+++ b/db2/lock/lock.c
@@ -8,7 +8,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock.c	10.52 (Sleepycat) 5/10/98";
+static const char sccsid[] = "@(#)lock.c	10.61 (Sleepycat) 1/3/99";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -23,16 +23,22 @@ static const char sccsid[] = "@(#)lock.c	10.52 (Sleepycat) 5/10/98";
 #include "db_page.h"
 #include "db_shash.h"
 #include "lock.h"
-#include "common_ext.h"
 #include "db_am.h"
+#include "txn_auto.h"
+#include "txn_ext.h"
+#include "common_ext.h"
 
 static void __lock_checklocker __P((DB_LOCKTAB *, struct __db_lock *, int));
 static void __lock_freeobj __P((DB_LOCKTAB *, DB_LOCKOBJ *));
-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_get_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
+    u_int32_t, const DBT *, db_lockmode_t, struct __db_lock **));
+static int  __lock_is_parent __P((u_int32_t, DB_TXN *));
+static int  __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *));
 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 int  __lock_vec_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
+	    u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **elistp));
 
 int
 lock_id(lt, idp)
@@ -41,6 +47,8 @@ lock_id(lt, idp)
 {
 	u_int32_t id;
 
+	LOCK_PANIC_CHECK(lt);
+
 	LOCK_LOCKREGION(lt);
 	if (lt->region->id >= DB_LOCK_MAXID)
 		lt->region->id = 0;
@@ -58,10 +66,37 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
 	int nlist;
 	DB_LOCKREQ *list, **elistp;
 {
+	return (__lock_vec_internal(lt,
+	    locker, NULL, flags, list, nlist, elistp));
+}
+
+int
+lock_tvec(lt, txn, flags, list, nlist, elistp)
+	DB_LOCKTAB *lt;
+	DB_TXN *txn;
+	u_int32_t flags;
+	int nlist;
+	DB_LOCKREQ *list, **elistp;
+{
+	return (__lock_vec_internal(lt,
+	    txn->txnid, txn, flags, list, nlist, elistp));
+}
+
+static int
+__lock_vec_internal(lt, locker, txn, flags, list, nlist, elistp)
+	DB_LOCKTAB *lt;
+	u_int32_t locker;
+	DB_TXN *txn;
+	u_int32_t flags;
+	int nlist;
+	DB_LOCKREQ *list, **elistp;
+{
 	struct __db_lock *lp;
-	DB_LOCKOBJ *sh_obj, *sh_locker;
+	DB_LOCKOBJ *sh_obj, *sh_locker, *sh_parent;
 	int i, ret, run_dd;
 
+	LOCK_PANIC_CHECK(lt);
+
 	/* Validate arguments. */
 	if ((ret =
 	    __db_fchk(lt->dbenv, "lock_vec", flags, DB_LOCK_NOWAIT)) != 0)
@@ -78,13 +113,43 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
 	for (i = 0; i < nlist && ret == 0; i++) {
 		switch (list[i].op) {
 		case DB_LOCK_GET:
-			ret = __lock_get_internal(lt, locker, flags,
+			ret = __lock_get_internal(lt, locker, txn, flags,
 			    list[i].obj, list[i].mode, &lp);
 			if (ret == 0) {
 				list[i].lock = LOCK_TO_OFFSET(lt, lp);
 				lt->region->nrequests++;
 			}
 			break;
+		case DB_LOCK_INHERIT:
+			/* Find the locker. */
+			if ((ret = __lock_getobj(lt, locker,
+			    NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
+				break;
+			if (txn == NULL || txn->parent == NULL) {
+				ret = EINVAL;
+				break;
+			}
+
+			if ((ret = __lock_getobj(lt, txn->parent->txnid,
+			    NULL, DB_LOCK_LOCKER, &sh_parent)) != 0)
+				break;
+
+			/*
+			 * Traverse all the locks held by this locker.  Remove
+			 * the locks from the locker's list and put them on the
+			 * parent's list.
+			 */
+			for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
+			    lp != NULL;
+			    lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
+				SH_LIST_REMOVE(lp, locker_links, __db_lock);
+				SH_LIST_INSERT_HEAD(&sh_parent->heldby, lp,
+				    locker_links, __db_lock);
+				lp->holder = txn->parent->txnid;
+			}
+			__lock_freeobj(lt, sh_locker);
+			lt->region->nlockers--;
+			break;
 		case DB_LOCK_PUT:
 			lp = OFFSET_TO_LOCK(lt, list[i].lock);
 			if (lp->holder != locker) {
@@ -93,8 +158,8 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
 			}
 			list[i].mode = lp->mode;
 
-			/* XXX Need to copy the object. ??? */
 			ret = __lock_put_internal(lt, lp, 0);
+			__lock_checklocker(lt, lp, 0);
 			break;
 		case DB_LOCK_PUT_ALL:
 			/* Find the locker. */
@@ -204,18 +269,25 @@ lock_get(lt, locker, flags, obj, lock_mode, lock)
 	struct __db_lock *lockp;
 	int ret;
 
+	LOCK_PANIC_CHECK(lt);
+
 	/* Validate arguments. */
-	if ((ret =
-	    __db_fchk(lt->dbenv, "lock_get", flags, DB_LOCK_NOWAIT)) != 0)
+	if ((ret = __db_fchk(lt->dbenv,
+	    "lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
 		return (ret);
 
 	LOCK_LOCKREGION(lt);
 
-	ret = __lock_validate_region(lt);
-	if (ret == 0 && (ret = __lock_get_internal(lt,
-	    locker, flags, obj, lock_mode, &lockp)) == 0) {
-		*lock = LOCK_TO_OFFSET(lt, lockp);
-		lt->region->nrequests++;
+	if ((ret = __lock_validate_region(lt)) == 0) {
+		if (LF_ISSET(DB_LOCK_UPGRADE))
+			lockp = OFFSET_TO_LOCK(lt, *lock);
+
+		if ((ret = __lock_get_internal(lt,
+		    locker, NULL, flags, obj, lock_mode, &lockp)) == 0) {
+			if (!LF_ISSET(DB_LOCK_UPGRADE))
+				*lock = LOCK_TO_OFFSET(lt, lockp);
+			lt->region->nrequests++;
+		}
 	}
 
 	UNLOCK_LOCKREGION(lt);
@@ -223,6 +295,42 @@ lock_get(lt, locker, flags, obj, lock_mode, lock)
 }
 
 int
+lock_tget(lt, txn, flags, obj, lock_mode, lock)
+	DB_LOCKTAB *lt;
+	DB_TXN *txn;
+	u_int32_t flags;
+	const DBT *obj;
+	db_lockmode_t lock_mode;
+	DB_LOCK *lock;
+{
+	struct __db_lock *lockp;
+	int ret;
+
+	LOCK_PANIC_CHECK(lt);
+
+	/* Validate arguments. */
+	if ((ret = __db_fchk(lt->dbenv,
+	    "lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
+		return (ret);
+
+	LOCK_LOCKREGION(lt);
+
+	if ((ret = __lock_validate_region(lt)) == 0) {
+		if (LF_ISSET(DB_LOCK_UPGRADE))
+			lockp = OFFSET_TO_LOCK(lt, *lock);
+
+		if ((ret = __lock_get_internal(lt,
+		    txn->txnid, txn, flags, obj, lock_mode, &lockp)) == 0) {
+			if (!LF_ISSET(DB_LOCK_UPGRADE))
+				*lock = LOCK_TO_OFFSET(lt, lockp);
+			lt->region->nrequests++;
+		}
+	}
+
+	UNLOCK_LOCKREGION(lt);
+	return (ret);
+}
+int
 lock_put(lt, lock)
 	DB_LOCKTAB *lt;
 	DB_LOCK lock;
@@ -230,6 +338,8 @@ lock_put(lt, lock)
 	struct __db_lock *lockp;
 	int ret, run_dd;
 
+	LOCK_PANIC_CHECK(lt);
+
 	LOCK_LOCKREGION(lt);
 
 	if ((ret = __lock_validate_region(lt)) != 0)
@@ -261,7 +371,6 @@ __lock_put_internal(lt, lockp, do_all)
 	struct __db_lock *lockp;
 	int do_all;
 {
-	struct __db_lock *lp_w, *lp_h, *next_waiter;
 	DB_LOCKOBJ *sh_obj;
 	int state_changed;
 
@@ -293,39 +402,7 @@ __lock_put_internal(lt, lockp, do_all)
 	else
 		SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock);
 
-	/*
-	 * We need to do lock promotion.  We also need to determine if
-	 * we're going to need to run the deadlock detector again.  If
-	 * we release locks, and there are waiters, but no one gets promoted,
-	 * then we haven't fundamentally changed the lockmgr state, so
-	 * we may still have a deadlock and we have to run again.  However,
-	 * if there were no waiters, or we actually promoted someone, then
-	 * we are OK and we don't have to run it immediately.
-	 */
-	for (lp_w = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock),
-	    state_changed = lp_w == NULL;
-	    lp_w != NULL;
-	    lp_w = next_waiter) {
-		next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);
-		for (lp_h = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
-		    lp_h != NULL;
-		    lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {
-			if (CONFLICTS(lt, lp_h->mode, lp_w->mode) &&
-			    lp_h->holder != lp_w->holder)
-				break;
-		}
-		if (lp_h != NULL)	/* Found a conflict. */
-			break;
-
-		/* No conflict, promote the waiting lock. */
-		SH_TAILQ_REMOVE(&sh_obj->waiters, lp_w, links, __db_lock);
-		lp_w->status = DB_LSTAT_PENDING;
-		SH_TAILQ_INSERT_TAIL(&sh_obj->holders, lp_w, links);
-
-		/* Wake up waiter. */
-		(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
-		state_changed = 1;
-	}
+	state_changed = __lock_promote(lt, sh_obj);
 
 	/* Check if object should be reclaimed. */
 	if (SH_TAILQ_FIRST(&sh_obj->holders, __db_lock) == NULL) {
@@ -354,9 +431,10 @@ __lock_put_internal(lt, lockp, do_all)
 }
 
 static int
-__lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
+__lock_get_internal(lt, locker, txn, flags, obj, lock_mode, lockp)
 	DB_LOCKTAB *lt;
 	u_int32_t locker, flags;
+	DB_TXN *txn;
 	const DBT *obj;
 	db_lockmode_t lock_mode;
 	struct __db_lock **lockp;
@@ -365,13 +443,13 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 	DB_LOCKOBJ *sh_obj, *sh_locker;
 	DB_LOCKREGION *lrp;
 	size_t newl_off;
-	int ihold, ret;
+	int ihold, no_dd, ret;
+
+	no_dd = ret = 0;
 
-	ret = 0;
 	/*
 	 * Check that lock mode is valid.
 	 */
-
 	lrp = lt->region;
 	if ((u_int32_t)lock_mode >= lrp->nmodes) {
 		__db_err(lt->dbenv,
@@ -423,20 +501,28 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 	 * lock, then we guarantee deadlock.
 	 *
 	 * In case of conflict, we put the new lock on the end of the waiters
-	 * list.
+	 * list, unless we are upgrading in which case the locker goes on the
+	 * front of the list.
 	 */
 	ihold = 0;
 	for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
 	    lp != NULL;
 	    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
-		if (locker == lp->holder) {
+		if (locker == lp->holder ||
+		    __lock_is_parent(lp->holder, txn)) {
 			if (lp->mode == lock_mode &&
 			    lp->status == DB_LSTAT_HELD) {
-				/* Lock is held, just inc the ref count. */
+				if (LF_ISSET(DB_LOCK_UPGRADE))
+					goto upgrade;
+
+				/*
+				 * Lock is held, so we can increment the
+				 * reference count and return this lock.
+				 */
 				lp->refcount++;
+				*lockp = lp;
 				SH_TAILQ_INSERT_HEAD(&lrp->free_locks,
 				    newl, links, __db_lock);
-				*lockp = lp;
 				return (0);
 			} else
 				ihold = 1;
@@ -444,6 +530,21 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 			break;
     	}
 
+	/*
+	 * If we are upgrading, then there are two scenarios.  Either
+	 * we had no conflicts, so we can do the upgrade.  Or, there
+	 * is a conflict and we should wait at the HEAD of the waiters
+	 * list.
+	 */
+	if (LF_ISSET(DB_LOCK_UPGRADE)) {
+		if (lp == NULL)
+			goto upgrade;
+
+		/* There was a conflict, wait. */
+		SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock);
+		goto wait;
+	}
+
 	if (lp == NULL && !ihold)
 		for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);
 		    lp != NULL;
@@ -464,31 +565,35 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 	}
 
 	/*
-	 * This is really a blocker for the process, so initialize it
-	 * set.  That way the current process will block when it tries
-	 * to get it and the waking process will release it.
-	 */
-	(void)__db_mutex_init(&newl->mutex,
-	    MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
-	(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
-
-	/*
-	 * Now, insert the lock onto its locker's list.
+	 * Now, insert the lock onto its locker's list.  If the locker does
+	 * not currently hold any locks, there's no reason to run a deadlock
+	 * detector, save that information.
 	 */
 	if ((ret =
 	    __lock_getobj(lt, locker, NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
 		return (ret);
+	no_dd = SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL;
 
 	lrp = lt->region;
 	SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock);
 
 	if (lp != NULL) {
+		/*
+		 * This is really a blocker for the process, so initialize it
+		 * set.  That way the current process will block when it tries
+		 * to get it and the waking process will release it.
+		 */
+wait:		(void)__db_mutex_init(&newl->mutex,
+		    MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
+		(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
+
 		newl->status = DB_LSTAT_WAITING;
 		lrp->nconflicts++;
+
 		/*
-		 * We are about to wait; must release the region mutex.
-		 * Then, when we wakeup, we need to reacquire the region
-		 * mutex before continuing.
+		 * We are about to wait; must release the region mutex.  Then,
+		 * when we wakeup, we need to reacquire the region mutex before
+		 * continuing.
 		 */
 		if (lrp->detect == DB_LOCK_NORUN)
 			lt->region->need_dd = 1;
@@ -498,13 +603,19 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 		 * We are about to wait; before waiting, see if the deadlock
 		 * detector should be run.
 		 */
-		if (lrp->detect != DB_LOCK_NORUN)
-			ret = lock_detect(lt, 0, lrp->detect);
+		if (lrp->detect != DB_LOCK_NORUN && !no_dd)
+			(void)lock_detect(lt, 0, lrp->detect);
 
 		(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
 
 		LOCK_LOCKREGION(lt);
 		if (newl->status != DB_LSTAT_PENDING) {
+			/*
+			 * If this lock errored due to a deadlock, then
+			 * we have waiters that require promotion.
+			 */
+			if (newl->status == DB_LSTAT_ABORTED)
+				(void)__lock_promote(lt, sh_obj);
 			/* Return to free list. */
 			__lock_checklocker(lt, newl, 0);
 			SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links,
@@ -522,12 +633,31 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
 			}
 			newl->status = DB_LSTAT_FREE;
 			newl = NULL;
+		} else if (LF_ISSET(DB_LOCK_UPGRADE)) {
+			/*
+			 * The lock that was just granted got put on the
+			 * holders list.  Since we're upgrading some other
+			 * lock, we've got to remove it here.
+			 */
+			SH_TAILQ_REMOVE(&sh_obj->holders,
+			    newl, links, __db_lock);
+			goto upgrade;
 		} else
 			newl->status = DB_LSTAT_HELD;
 	}
 
 	*lockp = newl;
 	return (ret);
+
+upgrade:
+	/*
+	 * This was an upgrade, so return the new lock to the free list and
+	 * upgrade the mode.
+	 */
+	(*lockp)->mode = lock_mode;
+	newl->status = DB_LSTAT_FREE;
+	SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links, __db_lock);
+	return (0);
 }
 
 /*
@@ -788,3 +918,117 @@ __lock_freeobj(lt, obj)
 		__db_shalloc_free(lt->mem, SH_DBT_PTR(&obj->lockobj));
 	SH_TAILQ_INSERT_HEAD(&lt->region->free_objs, obj, links, __db_lockobj);
 }
+
+/*
+ * __lock_downgrade --
+ *	Used by the concurrent access product to downgrade write locks
+ * back to iwrite locks.
+ *
+ * PUBLIC: int __lock_downgrade __P((DB_LOCKTAB *,
+ * PUBLIC:     DB_LOCK, db_lockmode_t, u_int32_t));
+ */
+int
+__lock_downgrade(lt, lock, new_mode, flags)
+	DB_LOCKTAB *lt;
+	DB_LOCK lock;
+	db_lockmode_t new_mode;
+	u_int32_t flags;
+{
+	struct __db_lock *lockp;
+	DB_LOCKOBJ *obj;
+	int ret;
+
+	COMPQUIET(flags, 0);
+	LOCK_PANIC_CHECK(lt);
+	LOCK_LOCKREGION(lt);
+
+	if ((ret = __lock_validate_region(lt)) == 0) {
+		lockp = OFFSET_TO_LOCK(lt, lock);
+		lockp->mode = new_mode;
+
+		/* Get the object associated with this lock. */
+		obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
+		(void)__lock_promote(lt, obj);
+		++lt->region->nreleases;
+	}
+
+	UNLOCK_LOCKREGION(lt);
+
+	return (ret);
+}
+
+/*
+ * __lock_promote --
+ *
+ * Look through the waiters and holders lists and decide which (if any)
+ * locks can be promoted.   Promote any that are eligible.
+ */
+static int
+__lock_promote(lt, obj)
+	DB_LOCKTAB *lt;
+	DB_LOCKOBJ *obj;
+{
+	struct __db_lock *lp_w, *lp_h, *next_waiter;
+	int state_changed, waiter_is_txn;
+
+	/*
+	 * We need to do lock promotion.  We also need to determine if
+	 * we're going to need to run the deadlock detector again.  If
+	 * we release locks, and there are waiters, but no one gets promoted,
+	 * then we haven't fundamentally changed the lockmgr state, so
+	 * we may still have a deadlock and we have to run again.  However,
+	 * if there were no waiters, or we actually promoted someone, then
+	 * we are OK and we don't have to run it immediately.
+	 *
+	 * During promotion, we look for state changes so we can return
+	 * this information to the caller.
+	 */
+	for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock),
+	    state_changed = lp_w == NULL;
+	    lp_w != NULL;
+	    lp_w = next_waiter) {
+		waiter_is_txn = TXN_IS_HOLDING(lp_w);
+		next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);
+		for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock);
+		    lp_h != NULL;
+		    lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {
+			if (CONFLICTS(lt, lp_h->mode, lp_w->mode) &&
+			    lp_h->holder != lp_w->holder &&
+			    !(waiter_is_txn &&
+			    TXN_IS_HOLDING(lp_h) &&
+			    __txn_is_ancestor(lt->dbenv->tx_info,
+			        lp_h->txnoff, lp_w->txnoff)))
+				break;
+		}
+		if (lp_h != NULL)	/* Found a conflict. */
+			break;
+
+		/* No conflict, promote the waiting lock. */
+		SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock);
+		lp_w->status = DB_LSTAT_PENDING;
+		SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links);
+
+		/* Wake up waiter. */
+		(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
+		state_changed = 1;
+	}
+
+	return (state_changed);
+}
+
+static int
+__lock_is_parent(locker, txn)
+	u_int32_t locker;
+	DB_TXN *txn;
+{
+	DB_TXN *t;
+
+	if (txn == NULL)
+		return (0);
+
+	for (t = txn->parent; t != NULL; t = t->parent)
+		if (t->txnid == locker)
+			return (1);
+
+	return (0);
+}
diff --git a/db2/lock/lock_conflict.c b/db2/lock/lock_conflict.c
index 870aa0dc17..4be858af7a 100644
--- a/db2/lock/lock_conflict.c
+++ b/db2/lock/lock_conflict.c
@@ -8,7 +8,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_conflict.c	10.3 (Sleepycat) 4/10/98";
+static const char sccsid[] = "@(#)lock_conflict.c	10.4 (Sleepycat) 11/20/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -29,11 +29,11 @@ const u_int8_t db_rw_conflicts[] = {
 };
 
 const u_int8_t db_riw_conflicts[] = {
-	/*		N   	S   	X  	IS  	IX	SIX */
+	/*		N   	S   	X  	IX  	IS	SIX */
 	/*   N */	0,	0,	0,	0,	0,	0,
-	/*   S */	0,	0,	1,	0,	1,	1,
+	/*   S */	0,	0,	1,	1,	0,	1,
 	/*   X */	1,	1,	1,	1,	1,	1,
-	/*  IS */	0,	0,	1,	0,	0,	0,
 	/*  IX */	0,	1,	1,	0,	0,	0,
+	/*  IS */	0,	0,	1,	0,	0,	0,
 	/* SIX */	0,	1,	1,	0,	0,	0
 };
diff --git a/db2/lock/lock_deadlock.c b/db2/lock/lock_deadlock.c
index 4de492944e..8b2f91bc9e 100644
--- a/db2/lock/lock_deadlock.c
+++ b/db2/lock/lock_deadlock.c
@@ -8,7 +8,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_deadlock.c	10.32 (Sleepycat) 4/26/98";
+static const char sccsid[] = "@(#)lock_deadlock.c	10.37 (Sleepycat) 10/4/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -69,6 +69,8 @@ lock_detect(lt, flags, atype)
 	u_int32_t *bitmap, *deadlock, i, killid, nentries, nlockers;
 	int do_pass, ret;
 
+	LOCK_PANIC_CHECK(lt);
+
 	/* Validate arguments. */
 	if ((ret =
 	    __db_fchk(lt->dbenv, "lock_detect", flags, DB_LOCK_CONFLICT)) != 0)
@@ -176,8 +178,8 @@ lock_detect(lt, flags, atype)
 			    "warning: unable to abort locker %lx",
 			    (u_long)idmap[killid].id);
 	}
-	__db_free(bitmap);
-	__db_free(idmap);
+	__os_free(bitmap, 0);
+	__os_free(idmap, 0);
 
 	return (ret);
 }
@@ -198,7 +200,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;
+	int is_first, ret;
 
 	lt = dbenv->lk_info;
 
@@ -230,25 +232,20 @@ retry:	count = lt->region->nlockers;
 	 * We can probably save the malloc's between iterations just
 	 * reallocing if necessary because count grew by too much.
 	 */
-	if ((bitmap = (u_int32_t *)__db_calloc((size_t)count,
-	    sizeof(u_int32_t) * nentries)) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
-		return (ENOMEM);
-	}
+	if ((ret = __os_calloc((size_t)count,
+	    sizeof(u_int32_t) * nentries, &bitmap)) != 0)
+		return (ret);
 
-	if ((tmpmap =
-	    (u_int32_t *)__db_calloc(sizeof(u_int32_t), nentries)) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
-		__db_free(bitmap);
-		return (ENOMEM);
+	if ((ret = __os_calloc(sizeof(u_int32_t), nentries, &tmpmap)) != 0) {
+		__os_free(bitmap, sizeof(u_int32_t) * nentries);
+		return (ret);
 	}
 
-	if ((id_array = (locker_info *)__db_calloc((size_t)count,
-	    sizeof(locker_info))) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
-		__db_free(bitmap);
-		__db_free(tmpmap);
-		return (ENOMEM);
+	if ((ret =
+	    __os_calloc((size_t)count, sizeof(locker_info), &id_array)) != 0) {
+		__os_free(bitmap, count * sizeof(u_int32_t) * nentries);
+		__os_free(tmpmap, sizeof(u_int32_t) * nentries);
+		return (ret);
 	}
 
 	/*
@@ -256,9 +253,9 @@ retry:	count = lt->region->nlockers;
 	 */
 	LOCK_LOCKREGION(lt);
 	if (lt->region->nlockers > count) {
-		__db_free(bitmap);
-		__db_free(tmpmap);
-		__db_free(id_array);
+		__os_free(bitmap, count * sizeof(u_int32_t) * nentries);
+		__os_free(tmpmap, sizeof(u_int32_t) * nentries);
+		__os_free(id_array, count * sizeof(locker_info));
 		goto retry;
 	}
 
@@ -383,7 +380,7 @@ retry:	count = lt->region->nlockers;
 	*nlockers = id;
 	*idmap = id_array;
 	*bmp = bitmap;
-	__db_free(tmpmap);
+	__os_free(tmpmap, sizeof(u_int32_t) * nentries);
 	return (0);
 }
 
@@ -434,8 +431,21 @@ __dd_abort(dbenv, info)
 		goto out;
 
 	lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
-	if (LOCK_TO_OFFSET(lt, lockp) != info->last_lock ||
-	    lockp == NULL || lockp->status != DB_LSTAT_WAITING)
+
+	/*
+	 * It's possible that this locker was already aborted.
+	 * If that's the case, make sure that we remove its
+	 * locker from the hash table.
+	 */
+	if (lockp == NULL) {
+		HASHREMOVE_EL(lt->hashtab, __db_lockobj,
+		    links, lockerp, lt->region->table_size, __lock_lhash);
+		SH_TAILQ_INSERT_HEAD(&lt->region->free_objs,
+		    lockerp, links, __db_lockobj);
+		lt->region->nlockers--;
+		goto out;
+	} else if (LOCK_TO_OFFSET(lt, lockp) != info->last_lock ||
+	    lockp->status != DB_LSTAT_WAITING)
 		goto out;
 
 	/* Abort lock, take it off list, and wake up this lock. */
@@ -460,17 +470,17 @@ __dd_debug(dbenv, idmap, bitmap, nlockers)
 	u_int32_t *bitmap, nlockers;
 {
 	u_int32_t i, j, *mymap, nentries;
+	int ret;
 	char *msgbuf;
 
 	__db_err(dbenv, "Waitsfor array");
 	__db_err(dbenv, "waiter\twaiting on");
-	/*
-	 * Allocate space to print 10 bytes per item waited on.
-	 */
-	if ((msgbuf = (char *)__db_malloc((nlockers + 1) * 10 + 64)) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
+
+	/* Allocate space to print 10 bytes per item waited on. */
+#undef	MSGBUF_LEN
+#define	MSGBUF_LEN ((nlockers + 1) * 10 + 64)
+	if ((ret = __os_malloc(MSGBUF_LEN, NULL, &msgbuf)) != 0)
 		return;
-	}
 
 	nentries = ALIGN(nlockers, 32) / 32;
 	for (mymap = bitmap, i = 0; i < nlockers; i++, mymap += nentries) {
@@ -487,6 +497,6 @@ __dd_debug(dbenv, idmap, bitmap, nlockers)
 		__db_err(dbenv, msgbuf);
 	}
 
-	__db_free(msgbuf);
+	__os_free(msgbuf, MSGBUF_LEN);
 }
 #endif
diff --git a/db2/lock/lock_region.c b/db2/lock/lock_region.c
index b597560744..613a6cefb2 100644
--- a/db2/lock/lock_region.c
+++ b/db2/lock/lock_region.c
@@ -8,7 +8,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_region.c	10.15 (Sleepycat) 6/2/98";
+static const char sccsid[] = "@(#)lock_region.c	10.21 (Sleepycat) 10/19/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -29,7 +29,8 @@ 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 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 *));
 
@@ -55,10 +56,8 @@ lock_open(path, flags, mode, dbenv, ltp)
 		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);
-	}
+	if ((ret = __os_calloc(1, sizeof(DB_LOCKTAB), &lt)) != 0)
+		return (ret);
 	lt->dbenv = dbenv;
 
 	/* Grab the values that we need to compute the region size. */
@@ -82,7 +81,7 @@ lock_open(path, flags, mode, dbenv, ltp)
 	if (path == NULL)
 		lt->reginfo.path = NULL;
 	else
-		if ((lt->reginfo.path = (char *)__db_strdup(path)) == NULL)
+		if ((ret = __os_strdup(path, &lt->reginfo.path)) != 0)
 			goto err;
 	lt->reginfo.file = DB_DEFAULT_LOCK_FILE;
 	lt->reginfo.mode = mode;
@@ -147,12 +146,27 @@ err:	if (lt->reginfo.addr != NULL) {
 	}
 
 	if (lt->reginfo.path != NULL)
-		FREES(lt->reginfo.path);
-	FREE(lt, sizeof(*lt));
+		__os_freestr(lt->reginfo.path);
+	__os_free(lt, sizeof(*lt));
 	return (ret);
 }
 
 /*
+ * __lock_panic --
+ *	Panic a lock region.
+ *
+ * PUBLIC: void __lock_panic __P((DB_ENV *));
+ */
+void
+__lock_panic(dbenv)
+	DB_ENV *dbenv;
+{
+	if (dbenv->lk_info != NULL)
+		dbenv->lk_info->region->hdr.panic = 1;
+}
+
+
+/*
  * __lock_tabinit --
  *	Initialize the lock region.
  */
@@ -254,12 +268,14 @@ lock_close(lt)
 {
 	int ret;
 
+	LOCK_PANIC_CHECK(lt);
+
 	if ((ret = __db_rdetach(&lt->reginfo)) != 0)
 		return (ret);
 
 	if (lt->reginfo.path != NULL)
-		FREES(lt->reginfo.path);
-	FREE(lt, sizeof(*lt));
+		__os_freestr(lt->reginfo.path);
+	__os_free(lt, sizeof(*lt));
 
 	return (0);
 }
@@ -276,12 +292,12 @@ lock_unlink(path, force, dbenv)
 	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);
+	if (path != NULL && (ret = __os_strdup(path, &reginfo.path)) != 0)
+		return (ret);
 	reginfo.file = DB_DEFAULT_LOCK_FILE;
 	ret = __db_runlink(&reginfo, force);
 	if (reginfo.path != NULL)
-		FREES(reginfo.path);
+		__os_freestr(reginfo.path);
 	return (ret);
 }
 
@@ -463,13 +479,14 @@ lock_stat(lt, gspp, db_malloc)
 	void *(*db_malloc) __P((size_t));
 {
 	DB_LOCKREGION *rp;
+	int ret;
 
 	*gspp = NULL;
 
-	if ((*gspp = db_malloc == NULL ?
-	    (DB_LOCK_STAT *)__db_malloc(sizeof(**gspp)) :
-	    (DB_LOCK_STAT *)db_malloc(sizeof(**gspp))) == NULL)
-		return (ENOMEM);
+	LOCK_PANIC_CHECK(lt);
+
+	if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
+		return (ret);
 
 	/* Copy out the global statistics. */
 	LOCK_LOCKREGION(lt);
@@ -632,15 +649,15 @@ __lock_dump_region(lt, area, fp)
 		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,
+			fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp,
 			    (u_long)lp->holder, (u_long)lp->mode,
-			    __lock_dump_status(lp->status), (u_int)lp->obj);
+			    __lock_dump_status(lp->status), (u_long)lp->obj);
 
 		fprintf(fp, "%s\nObject free list\n", DB_LINE);
 		for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
 		    op != NULL;
 		    op = SH_TAILQ_NEXT(op, links, __db_lockobj))
-			fprintf(fp, "0x%x\n", (u_int)op);
+			fprintf(fp, "0x%lx\n", (u_long)op);
 	}
 
 	if (LF_ISSET(LOCK_DUMP_MEM))
diff --git a/db2/lock/lock_util.c b/db2/lock/lock_util.c
index 7274a50422..29da75b8a8 100644
--- a/db2/lock/lock_util.c
+++ b/db2/lock/lock_util.c
@@ -8,7 +8,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)lock_util.c	10.9 (Sleepycat) 4/26/98";
+static const char sccsid[] = "@(#)lock_util.c	10.10 (Sleepycat) 9/20/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -75,7 +75,7 @@ __lock_locker_cmp(locker, lock_obj)
  * 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
+ * We know that DB uses DB_LOCK_ILOCK types 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
@@ -107,7 +107,7 @@ u_int32_t
 __lock_ohash(dbt)
 	const DBT *dbt;
 {
-	if (dbt->size == sizeof(struct __db_ilock))
+	if (dbt->size == sizeof(DB_LOCK_ILOCK))
 		FAST_HASH(dbt->data);
 
 	return (__ham_func5(dbt->data, dbt->size));
@@ -131,7 +131,7 @@ __lock_lhash(lock_obj)
 		return (tmp);
 	}
 
-	if (lock_obj->lockobj.size == sizeof(struct __db_ilock))
+	if (lock_obj->lockobj.size == sizeof(DB_LOCK_ILOCK))
 		FAST_HASH(obj_data);
 
 	return (__ham_func5(obj_data, lock_obj->lockobj.size));