summaryrefslogtreecommitdiff
path: root/db/lock
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2007-07-30 11:58:31 +0300
committerPanu Matilainen <pmatilai@redhat.com>2007-07-30 11:58:31 +0300
commitcab228435bde1b5496522c03a4ce9840f2ef3701 (patch)
tree2c37b65d176e2de097603333f4de071c31eeff3d /db/lock
parent2d07882d45e9e575c00f8f402d4c7271bb65cfe9 (diff)
downloadrpm-cab228435bde1b5496522c03a4ce9840f2ef3701.tar.gz
rpm-cab228435bde1b5496522c03a4ce9840f2ef3701.tar.bz2
rpm-cab228435bde1b5496522c03a4ce9840f2ef3701.zip
Update internal BDB to version 4.6.18.
Diffstat (limited to 'db/lock')
-rw-r--r--db/lock/lock.c451
-rw-r--r--db/lock/lock_conflict.c34
-rw-r--r--db/lock/lock_deadlock.c231
-rw-r--r--db/lock/lock_failchk.c14
-rw-r--r--db/lock/lock_id.c170
-rw-r--r--db/lock/lock_list.c10
-rw-r--r--db/lock/lock_method.c33
-rw-r--r--db/lock/lock_region.c140
-rw-r--r--db/lock/lock_stat.c158
-rw-r--r--db/lock/lock_stub.c491
-rw-r--r--db/lock/lock_timer.c144
-rw-r--r--db/lock/lock_util.c5
12 files changed, 1313 insertions, 568 deletions
diff --git a/db/lock/lock.c b/db/lock/lock.c
index 03cd11831..3644f818b 100644
--- a/db/lock/lock.c
+++ b/db/lock/lock.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock.c,v 12.30 2006/08/24 14:46:10 bostic Exp $
+ * $Id: lock.c,v 12.44 2007/05/17 19:33:04 bostic Exp $
*/
#include "db_config.h"
@@ -14,17 +13,21 @@
#include "dbinc/log.h"
static int __lock_freelock __P((DB_LOCKTAB *,
- struct __db_lock *, u_int32_t, u_int32_t));
+ struct __db_lock *, DB_LOCKER *, u_int32_t));
static int __lock_getobj
__P((DB_LOCKTAB *, const DBT *, u_int32_t, int, DB_LOCKOBJ **));
-static int __lock_inherit_locks __P ((DB_LOCKTAB *, u_int32_t, u_int32_t));
-static int __lock_is_parent __P((DB_LOCKTAB *, u_int32_t, DB_LOCKER *));
+static int __lock_get_api __P((DB_ENV *,
+ u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
+static int __lock_inherit_locks __P ((DB_LOCKTAB *, DB_LOCKER *, u_int32_t));
+static int __lock_is_parent __P((DB_LOCKTAB *, roff_t, DB_LOCKER *));
static int __lock_put_internal __P((DB_LOCKTAB *,
struct __db_lock *, u_int32_t, u_int32_t));
static int __lock_put_nolock __P((DB_ENV *, DB_LOCK *, int *, u_int32_t));
static int __lock_remove_waiter __P((DB_LOCKTAB *,
DB_LOCKOBJ *, struct __db_lock *, db_status_t));
-static int __lock_trade __P((DB_ENV *, DB_LOCK *, u_int32_t));
+static int __lock_trade __P((DB_ENV *, DB_LOCK *, DB_LOCKER *));
+static int __lock_vec_api __P((DB_ENV *,
+ u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
static const char __db_lock_invalid[] = "%s: Lock is no longer valid";
static const char __db_locker_invalid[] = "Locker is not valid";
@@ -37,9 +40,9 @@ static const char __db_locker_invalid[] = "Locker is not valid";
* PUBLIC: u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
*/
int
-__lock_vec_pp(dbenv, locker, flags, list, nlist, elistp)
+__lock_vec_pp(dbenv, lid, flags, list, nlist, elistp)
DB_ENV *dbenv;
- u_int32_t locker, flags;
+ u_int32_t lid, flags;
int nlist;
DB_LOCKREQ *list, **elistp;
{
@@ -57,11 +60,27 @@ __lock_vec_pp(dbenv, locker, flags, list, nlist, elistp)
ENV_ENTER(dbenv, ip);
REPLICATION_WRAP(dbenv,
- (__lock_vec(dbenv, locker, flags, list, nlist, elistp)), ret);
+ (__lock_vec_api(dbenv, lid, flags, list, nlist, elistp)), ret);
ENV_LEAVE(dbenv, ip);
return (ret);
}
+static int
+__lock_vec_api(dbenv, lid, flags, list, nlist, elistp)
+ DB_ENV *dbenv;
+ u_int32_t lid, flags;
+ int nlist;
+ DB_LOCKREQ *list, **elistp;
+{
+ DB_LOCKER *sh_locker;
+ int ret;
+
+ if ((ret =
+ __lock_getlocker(dbenv->lk_handle, lid, 0, &sh_locker)) == 0)
+ ret = __lock_vec(dbenv, sh_locker, flags, list, nlist, elistp);
+ return (ret);
+}
+
/*
* __lock_vec --
* DB_ENV->lock_vec.
@@ -73,23 +92,22 @@ __lock_vec_pp(dbenv, locker, flags, list, nlist, elistp)
* all locks on a given object, and generating debugging information.
*
* PUBLIC: int __lock_vec __P((DB_ENV *,
- * PUBLIC: u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
+ * PUBLIC: DB_LOCKER *, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
*/
int
-__lock_vec(dbenv, locker, flags, list, nlist, elistp)
+__lock_vec(dbenv, sh_locker, flags, list, nlist, elistp)
DB_ENV *dbenv;
- u_int32_t locker, flags;
+ DB_LOCKER *sh_locker;
+ u_int32_t flags;
int nlist;
DB_LOCKREQ *list, **elistp;
{
struct __db_lock *lp, *next_lock;
- DB_LOCK lock;
- DB_LOCKER *sh_locker;
- DB_LOCKOBJ *sh_obj;
+ DB_LOCK lock; DB_LOCKOBJ *sh_obj;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
DBT *objlist, *np;
- u_int32_t lndx, ndx;
+ u_int32_t ndx;
int did_abort, i, ret, run_dd, upgrade, writes;
/* Check if locks have been globally turned off. */
@@ -112,11 +130,11 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
break;
}
ret = __lock_get_internal(lt,
- locker, flags, list[i].obj,
+ sh_locker, flags, list[i].obj,
list[i].mode, list[i].timeout, &list[i].lock);
break;
case DB_LOCK_INHERIT:
- ret = __lock_inherit_locks(lt, locker, flags);
+ ret = __lock_inherit_locks(lt, sh_locker, flags);
break;
case DB_LOCK_PUT:
ret = __lock_put_nolock(dbenv,
@@ -134,10 +152,7 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
* done any work), it's perfectly reasonable for there
* to be no locker; this is not an error.
*/
- LOCKER_LOCK(lt, region, locker, ndx);
- if ((ret = __lock_getlocker(lt,
- locker, ndx, 0, &sh_locker)) != 0 ||
- sh_locker == NULL ||
+ if (sh_locker == NULL ||
F_ISSET(sh_locker, DB_LOCKER_DELETED))
/*
* If ret is set, then we'll generate an
@@ -187,7 +202,8 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
locker_links, __db_lock);
sh_obj = (DB_LOCKOBJ *)
((u_int8_t *)lp + lp->obj);
- SHOBJECT_LOCK(lt, region, sh_obj, lndx);
+ ndx = sh_obj->indx;
+ OBJECT_LOCK_NDX(lt, ndx);
/*
* We are not letting lock_put_internal
* unlink the lock, so we'll have to
@@ -197,7 +213,9 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
if (IS_WRITELOCK(lp->mode))
sh_locker->nwrites--;
ret = __lock_put_internal(lt, lp,
- lndx, DB_LOCK_FREE | DB_LOCK_DOALL);
+ sh_obj->indx,
+ DB_LOCK_FREE | DB_LOCK_DOALL);
+ OBJECT_UNLOCK(lt, ndx);
if (ret != 0)
break;
continue;
@@ -230,7 +248,7 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
lock.gen = lp->gen;
F_SET(sh_locker, DB_LOCKER_INABORT);
if ((ret = __lock_get_internal(lt,
- locker, flags | DB_LOCK_UPGRADE,
+ sh_locker, flags | DB_LOCK_UPGRADE,
NULL, DB_LOCK_WRITE, 0, &lock)) !=0)
break;
}
@@ -251,6 +269,7 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
ndx, 0, &sh_obj)) != 0 || sh_obj == NULL) {
if (ret == 0)
ret = EINVAL;
+ OBJECT_UNLOCK(lt, ndx);
break;
}
@@ -280,11 +299,12 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
DB_LOCK_UNLINK |
DB_LOCK_NOPROMOTE | DB_LOCK_DOALL);
}
+ OBJECT_UNLOCK(lt, ndx);
break;
case DB_LOCK_TIMEOUT:
ret = __lock_set_timeout_internal(dbenv,
- locker, 0, DB_SET_TXN_NOW);
+ sh_locker, 0, DB_SET_TXN_NOW);
break;
case DB_LOCK_TRADE:
@@ -302,15 +322,11 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
* so heaven help you if you use this flag under
* any other circumstances.
*/
- ret = __lock_trade(dbenv, &list[i].lock, locker);
+ ret = __lock_trade(dbenv, &list[i].lock, sh_locker);
break;
#if defined(DEBUG) && defined(HAVE_STATISTICS)
case DB_LOCK_DUMP:
- /* Find the locker. */
- LOCKER_LOCK(lt, region, locker, ndx);
- if ((ret = __lock_getlocker(lt,
- locker, ndx, 0, &sh_locker)) != 0 ||
- sh_locker == NULL ||
+ if (sh_locker == NULL ||
F_ISSET(sh_locker, DB_LOCKER_DELETED))
break;
@@ -327,7 +343,7 @@ __lock_vec(dbenv, locker, flags, list, nlist, elistp)
}
if (ret == 0 && region->detect != DB_LOCK_NORUN &&
- (region->need_dd || LOCK_TIME_ISVALID(&region->next_timeout)))
+ (region->need_dd || timespecisset(&region->next_timeout)))
run_dd = 1;
LOCK_SYSTEM_UNLOCK(dbenv);
@@ -369,22 +385,50 @@ __lock_get_pp(dbenv, locker, flags, obj, lock_mode, lock)
ENV_ENTER(dbenv, ip);
REPLICATION_WRAP(dbenv,
- (__lock_get(dbenv, locker, flags, obj, lock_mode, lock)), ret);
+ (__lock_get_api(dbenv, locker, flags, obj, lock_mode, lock)), ret);
ENV_LEAVE(dbenv, ip);
return (ret);
}
+static int
+__lock_get_api(dbenv, locker, flags, obj, lock_mode, lock)
+ DB_ENV *dbenv;
+ u_int32_t locker, flags;
+ const DBT *obj;
+ db_lockmode_t lock_mode;
+ DB_LOCK *lock;
+{
+ DB_LOCKER *sh_locker;
+ DB_LOCKREGION *region;
+ int ret;
+
+ COMPQUIET(region, NULL);
+
+ region = dbenv->lk_handle->reginfo.primary;
+
+ LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
+ ret = __lock_getlocker_int(dbenv->lk_handle, locker, 0, &sh_locker);
+ UNLOCK_LOCKERS(dbenv, region);
+ if (ret == 0)
+ ret = __lock_get_internal(dbenv->lk_handle,
+ sh_locker, flags, obj, lock_mode, 0, lock);
+ LOCK_SYSTEM_UNLOCK(dbenv);
+ return (ret);
+}
+
/*
* __lock_get --
* DB_ENV->lock_get.
*
* PUBLIC: int __lock_get __P((DB_ENV *,
- * PUBLIC: u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
+ * PUBLIC: DB_LOCKER *, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
*/
int
__lock_get(dbenv, locker, flags, obj, lock_mode, lock)
DB_ENV *dbenv;
- u_int32_t locker, flags;
+ DB_LOCKER *locker;
+ u_int32_t flags;
const DBT *obj;
db_lockmode_t lock_mode;
DB_LOCK *lock;
@@ -410,13 +454,14 @@ __lock_get(dbenv, locker, flags, obj, lock_mode, lock)
* All the work for lock_get (and for the GET option of lock_vec) is done
* inside of lock_get_internal.
*
- * PUBLIC: int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, u_int32_t,
+ * PUBLIC: int __lock_get_internal __P((DB_LOCKTAB *, DB_LOCKER *, u_int32_t,
* PUBLIC: const DBT *, db_lockmode_t, db_timeout_t, DB_LOCK *));
*/
int
-__lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
+__lock_get_internal(lt, sh_locker, flags, obj, lock_mode, timeout, lock)
DB_LOCKTAB *lt;
- u_int32_t locker, flags;
+ DB_LOCKER *sh_locker;
+ u_int32_t flags;
const DBT *obj;
db_lockmode_t lock_mode;
db_timeout_t timeout;
@@ -424,12 +469,12 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
{
struct __db_lock *newl, *lp;
DB_ENV *dbenv;
- DB_LOCKER *sh_locker;
DB_LOCKOBJ *sh_obj;
DB_LOCKREGION *region;
DB_THREAD_INFO *ip;
- u_int32_t holder, locker_ndx, obj_ndx;
+ u_int32_t ndx;
int did_abort, ihold, grant_dirty, no_dd, ret, t_ret;
+ roff_t holder, sh_off;
/*
* We decide what action to take based on what locks are already held
@@ -450,6 +495,11 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
if (F_ISSET(dbenv, DB_ENV_NOLOCKING))
return (0);
+ if (sh_locker == NULL) {
+ __db_errx(dbenv, "Locker does not exist");
+ return (EINVAL);
+ }
+
no_dd = ret = 0;
newl = NULL;
sh_obj = NULL;
@@ -460,33 +510,27 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
(u_long)lock_mode);
return (EINVAL);
}
- if (LF_ISSET(DB_LOCK_UPGRADE))
- region->stat.st_nupgrade++;
- else if (!LF_ISSET(DB_LOCK_SWITCH))
- region->stat.st_nrequests++;
if (obj == NULL) {
DB_ASSERT(dbenv, LOCK_ISSET(*lock));
lp = R_ADDR(&lt->reginfo, lock->off);
sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
+ ndx = sh_obj->indx;
+ OBJECT_LOCK_NDX(lt, ndx);
} else {
/* Allocate a shared memory new object. */
OBJECT_LOCK(lt, region, obj, lock->ndx);
+ ndx = lock->ndx;
if ((ret = __lock_getobj(lt, obj, lock->ndx, 1, &sh_obj)) != 0)
goto err;
}
- /* Get the locker, we may need it to find our parent. */
- LOCKER_LOCK(lt, region, locker, locker_ndx);
- if ((ret = __lock_getlocker(lt, locker,
- locker_ndx, locker > DB_LOCK_MAXID ? 1 : 0, &sh_locker)) != 0)
- goto err;
-
- if (sh_locker == NULL) {
- __db_errx(dbenv, "Locker does not exist");
- ret = EINVAL;
- goto err;
- }
+#ifdef HAVE_STATISTICS
+ if (LF_ISSET(DB_LOCK_UPGRADE))
+ lt->obj_stat[ndx].st_nupgrade++;
+ else if (!LF_ISSET(DB_LOCK_SWITCH))
+ lt->obj_stat[ndx].st_nrequests++;
+#endif
/*
* Figure out if we can grant this lock or if it should wait.
@@ -526,9 +570,11 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
lp = NULL;
else
lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
+
+ sh_off = R_OFFSET(&lt->reginfo, sh_locker);
for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
DB_ASSERT(dbenv, lp->status != DB_LSTAT_FREE);
- if (locker == lp->holder) {
+ if (sh_off == lp->holder) {
if (lp->mode == lock_mode &&
lp->status == DB_LSTAT_HELD) {
if (LF_ISSET(DB_LOCK_UPGRADE))
@@ -586,7 +632,7 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
SH_TAILQ_FOREACH(
lp, &sh_obj->waiters, links, __db_lock)
if (CONFLICTS(lt, region, lp->mode,
- lock_mode) && locker != lp->holder)
+ lock_mode) && sh_off != lp->holder)
break;
/*
@@ -646,6 +692,7 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
case SECOND:
case GRANT:
/* Allocate a new lock. */
+ LOCK_LOCKS(dbenv, region);
if ((newl =
SH_TAILQ_FIRST(&region->free_locks, __db_lock)) == NULL) {
ret = __lock_nomem(dbenv, "locks");
@@ -653,9 +700,12 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
}
SH_TAILQ_REMOVE(&region->free_locks, newl, links, __db_lock);
+#ifdef HAVE_STATISTICS
/* Update new lock statistics. */
if (++region->stat.st_nlocks > region->stat.st_maxnlocks)
region->stat.st_maxnlocks = region->stat.st_nlocks;
+#endif
+ UNLOCK_LOCKS(dbenv, region);
/*
* Allocate a mutex if we do not have a mutex backing the lock.
@@ -674,10 +724,11 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)
MUTEX_LOCK(dbenv, newl->mtx_lock);
}
- newl->holder = locker;
+ newl->holder = R_OFFSET(&lt->reginfo, sh_locker);
newl->refcount = 1;
newl->mode = lock_mode;
newl->obj = (roff_t)SH_PTR_TO_OFF(newl, sh_obj);
+ newl->indx = sh_obj->indx;
/*
* Now, insert the lock onto its locker's list.
* If the locker does not currently hold any locks,
@@ -714,12 +765,16 @@ upgrade: lp = R_ADDR(&lt->reginfo, lock->off);
case SECOND:
if (LF_ISSET(DB_LOCK_NOWAIT)) {
ret = DB_LOCK_NOTGRANTED;
- region->stat.st_lock_nowait++;
+ STAT(region->stat.st_lock_nowait++);
goto err;
}
- if ((lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) == NULL)
+ if ((lp =
+ SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) == NULL) {
+ LOCK_OBJECTS(dbenv, region);
SH_TAILQ_INSERT_HEAD(&region->dd_objs,
sh_obj, dd_links, __db_lockobj);
+ UNLOCK_OBJECTS(dbenv, region);
+ }
switch (action) {
case HEAD:
SH_TAILQ_INSERT_HEAD(
@@ -736,15 +791,6 @@ upgrade: lp = R_ADDR(&lt->reginfo, lock->off);
DB_ASSERT(dbenv, 0);
}
- /* If we are switching drop the lock we had. */
- if (LF_ISSET(DB_LOCK_SWITCH) &&
- (ret = __lock_put_nolock(dbenv,
- lock, &ihold, DB_LOCK_NOWAITERS)) != 0) {
- (void)__lock_remove_waiter(
- lt, sh_obj, newl, DB_LSTAT_FREE);
- goto err;
- }
-
/*
* First check to see if this txn has expired.
* If not then see if the lock timeout is past
@@ -776,23 +822,35 @@ upgrade: lp = R_ADDR(&lt->reginfo, lock->off);
if (timeout != 0)
__lock_expires(dbenv, &sh_locker->lk_expire, timeout);
else
- LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);
+ timespecclear(&sh_locker->lk_expire);
- if (LOCK_TIME_ISVALID(&sh_locker->tx_expire) &&
+ if (timespecisset(&sh_locker->tx_expire) &&
(timeout == 0 || __lock_expired(dbenv,
&sh_locker->lk_expire, &sh_locker->tx_expire)))
sh_locker->lk_expire = sh_locker->tx_expire;
- if (LOCK_TIME_ISVALID(&sh_locker->lk_expire) &&
- (!LOCK_TIME_ISVALID(&region->next_timeout) ||
- LOCK_TIME_GREATER(
- &region->next_timeout, &sh_locker->lk_expire)))
+ if (timespecisset(&sh_locker->lk_expire) &&
+ (!timespecisset(&region->next_timeout) ||
+ timespeccmp(
+ &region->next_timeout, &sh_locker->lk_expire, >)))
region->next_timeout = sh_locker->lk_expire;
newl->status = DB_LSTAT_WAITING;
- region->stat.st_lock_wait++;
+ STAT(lt->obj_stat[ndx].st_lock_wait++);
/* We are about to block, deadlock detector must run. */
region->need_dd = 1;
+ OBJECT_UNLOCK(lt, sh_obj->indx);
+
+ /* If we are switching drop the lock we had. */
+ if (LF_ISSET(DB_LOCK_SWITCH) &&
+ (ret = __lock_put_nolock(dbenv,
+ lock, &ihold, DB_LOCK_NOWAITERS)) != 0) {
+ OBJECT_LOCK_NDX(lt, sh_obj->indx);
+ (void)__lock_remove_waiter(
+ lt, sh_obj, newl, DB_LSTAT_FREE);
+ goto err;
+ }
+
LOCK_SYSTEM_UNLOCK(dbenv);
/*
@@ -810,27 +868,30 @@ upgrade: lp = R_ADDR(&lt->reginfo, lock->off);
ip->dbth_state = THREAD_ACTIVE;
LOCK_SYSTEM_LOCK(dbenv);
+ ndx = sh_obj->indx;
+ OBJECT_LOCK_NDX(lt, ndx);
/* Turn off lock timeout. */
if (newl->status != DB_LSTAT_EXPIRED)
- LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);
+ timespecclear(&sh_locker->lk_expire);
switch (newl->status) {
case DB_LSTAT_ABORTED:
ret = DB_LOCK_DEADLOCK;
goto err;
case DB_LSTAT_EXPIRED:
-expired: SHOBJECT_LOCK(lt, region, sh_obj, obj_ndx);
- ret = __lock_put_internal(lt, newl,
- obj_ndx, DB_LOCK_UNLINK | DB_LOCK_FREE);
+expired: ret = __lock_put_internal(lt, newl,
+ ndx, DB_LOCK_UNLINK | DB_LOCK_FREE);
newl = NULL;
if (ret != 0)
goto err;
- if (LOCK_TIME_EQUAL(
- &sh_locker->lk_expire, &sh_locker->tx_expire))
- region->stat.st_ntxntimeouts++;
+#ifdef HAVE_STATISTICS
+ if (timespeccmp(
+ &sh_locker->lk_expire, &sh_locker->tx_expire, ==))
+ lt->obj_stat[ndx].st_ntxntimeouts++;
else
- region->stat.st_nlocktimeouts++;
+ lt->obj_stat[ndx].st_nlocktimeouts++;
+#endif
ret = DB_LOCK_NOTGRANTED;
goto err;
case DB_LSTAT_PENDING:
@@ -873,13 +934,15 @@ expired: SHOBJECT_LOCK(lt, region, sh_obj, obj_ndx);
F_SET(sh_locker, DB_LOCKER_DIRTY);
}
+ OBJECT_UNLOCK(lt, ndx);
return (0);
err: if (!LF_ISSET(DB_LOCK_UPGRADE | DB_LOCK_SWITCH))
LOCK_INIT(*lock);
-done: if (newl != NULL &&
- (t_ret = __lock_freelock(lt, newl, locker,
+done: OBJECT_UNLOCK(lt, ndx);
+ if (newl != NULL &&
+ (t_ret = __lock_freelock(lt, newl, sh_locker,
DB_LOCK_FREE | DB_LOCK_UNLINK)) != 0 && ret == 0)
ret = t_ret;
@@ -971,13 +1034,16 @@ __lock_put_nolock(dbenv, lock, runp, flags)
return (EINVAL);
}
+ OBJECT_LOCK_NDX(lt, lock->ndx);
ret = __lock_put_internal(lt,
lockp, lock->ndx, flags | DB_LOCK_UNLINK | DB_LOCK_FREE);
+ OBJECT_UNLOCK(lt, lock->ndx);
+
LOCK_INIT(*lock);
*runp = 0;
if (ret == 0 && region->detect != DB_LOCK_NORUN &&
- (region->need_dd || LOCK_TIME_ISVALID(&region->next_timeout)))
+ (region->need_dd || timespecisset(&region->next_timeout)))
*runp = 1;
return (ret);
@@ -1007,7 +1073,6 @@ __lock_downgrade(dbenv, lock, new_mode, flags)
DB_LOCKOBJ *obj;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- u_int32_t indx;
int ret;
PANIC_CHECK(dbenv);
@@ -1020,10 +1085,9 @@ __lock_downgrade(dbenv, lock, new_mode, flags)
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
- if (!LF_ISSET(DB_LOCK_NOREGION))
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_SYSTEM_LOCK(dbenv);
- region->stat.st_ndowngrade++;
+ STAT(region->stat.st_ndowngrade++);
lockp = R_ADDR(&lt->reginfo, lock->off);
if (lock->gen != lockp->gen) {
@@ -1032,15 +1096,8 @@ __lock_downgrade(dbenv, lock, new_mode, flags)
goto out;
}
- LOCKER_LOCK(lt, region, lockp->holder, indx);
+ sh_locker = R_ADDR(&lt->reginfo, lockp->holder);
- if ((ret = __lock_getlocker(lt, lockp->holder,
- indx, 0, &sh_locker)) != 0 || sh_locker == NULL) {
- if (ret == 0)
- ret = EINVAL;
- __db_errx(dbenv, __db_locker_invalid);
- goto out;
- }
if (IS_WRITELOCK(lockp->mode) && !IS_WRITELOCK(new_mode))
sh_locker->nwrites--;
@@ -1049,10 +1106,12 @@ __lock_downgrade(dbenv, lock, new_mode, flags)
/* Get the object associated with this lock. */
obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
+ OBJECT_LOCK_NDX(lt, obj->indx);
+ lt->obj_stat[obj->indx].st_ndowngrade++;
ret = __lock_promote(lt, obj, NULL, LF_ISSET(DB_LOCK_NOWAITERS));
+ OBJECT_UNLOCK(lt, obj->indx);
-out: if (!LF_ISSET(DB_LOCK_NOREGION))
- LOCK_SYSTEM_UNLOCK(dbenv);
+out: LOCK_SYSTEM_UNLOCK(dbenv);
return (ret);
}
@@ -1063,10 +1122,13 @@ __lock_put_internal(lt, lockp, obj_ndx, flags)
struct __db_lock *lockp;
u_int32_t obj_ndx, flags;
{
+ DB_ENV *dbenv;
DB_LOCKOBJ *sh_obj;
DB_LOCKREGION *region;
int ret, state_changed;
+ COMPQUIET(dbenv, NULL);
+ dbenv = lt->dbenv;
region = lt->reginfo.primary;
ret = state_changed = 0;
@@ -1077,14 +1139,20 @@ __lock_put_internal(lt, lockp, obj_ndx, flags)
* already been done; all we need to do is return it to the
* free list.
*/
- (void)__lock_freelock(lt, lockp, 0, DB_LOCK_FREE);
+ (void)__lock_freelock(lt, lockp, NULL, DB_LOCK_FREE);
return (0);
}
+ /*
+ * If we are using the multiple mutex implementation then we
+ * update these counters unsafely.
+ */
+#ifdef HAVE_STATISTICS
if (LF_ISSET(DB_LOCK_DOALL))
- region->stat.st_nreleases += lockp->refcount;
+ lt->obj_stat[obj_ndx].st_nreleases += lockp->refcount;
else
- region->stat.st_nreleases++;
+ lt->obj_stat[obj_ndx].st_nreleases++;
+#endif
if (!LF_ISSET(DB_LOCK_DOALL) && lockp->refcount > 1) {
lockp->refcount--;
@@ -1125,18 +1193,22 @@ __lock_put_internal(lt, lockp, obj_ndx, flags)
SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) {
SH_TAILQ_REMOVE(
&lt->obj_tab[obj_ndx], sh_obj, links, __db_lockobj);
+ LOCK_OBJECTS(dbenv, region);
if (sh_obj->lockobj.size > sizeof(sh_obj->objdata))
- __db_shalloc_free(&lt->reginfo,
+ __env_alloc_free(&lt->reginfo,
SH_DBT_PTR(&sh_obj->lockobj));
SH_TAILQ_INSERT_HEAD(
&region->free_objs, sh_obj, links, __db_lockobj);
- region->stat.st_nobjects--;
+ sh_obj->generation++;
+ STAT(region->stat.st_nobjects--);
+ UNLOCK_OBJECTS(dbenv, region);
state_changed = 1;
}
/* Free lock. */
if (LF_ISSET(DB_LOCK_UNLINK | DB_LOCK_FREE))
- ret = __lock_freelock(lt, lockp, lockp->holder, flags);
+ ret = __lock_freelock(lt, lockp,
+ R_ADDR(&lt->reginfo, lockp->holder), flags);
/*
* If we did not promote anyone; we need to run the deadlock
@@ -1154,27 +1226,20 @@ __lock_put_internal(lt, lockp, obj_ndx, flags)
*
*/
static int
-__lock_freelock(lt, lockp, locker, flags)
+__lock_freelock(lt, lockp, sh_locker, flags)
DB_LOCKTAB *lt;
struct __db_lock *lockp;
- u_int32_t locker, flags;
+ DB_LOCKER *sh_locker;
+ u_int32_t flags;
{
DB_ENV *dbenv;
- DB_LOCKER *sh_locker;
DB_LOCKREGION *region;
- u_int32_t indx;
int ret;
dbenv = lt->dbenv;
region = lt->reginfo.primary;
if (LF_ISSET(DB_LOCK_UNLINK)) {
- LOCKER_LOCK(lt, region, locker, indx);
- if ((ret = __lock_getlocker(lt,
- locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) {
- __db_errx(dbenv, __db_locker_invalid);
- return (ret == 0 ? EINVAL : ret);
- }
SH_LIST_REMOVE(lockp, locker_links, __db_lock);
if (lockp->status == DB_LSTAT_HELD) {
@@ -1196,9 +1261,11 @@ __lock_freelock(lt, lockp, locker, flags)
(ret = __mutex_free(dbenv, &lockp->mtx_lock)) != 0)
return (ret);
lockp->status = DB_LSTAT_FREE;
+ LOCK_LOCKS(dbenv, region);
SH_TAILQ_INSERT_HEAD(
&region->free_locks, lockp, links, __db_lock);
- region->stat.st_nlocks--;
+ STAT(region->stat.st_nlocks--);
+ UNLOCK_LOCKS(dbenv, region);
}
return (0);
@@ -1225,37 +1292,47 @@ __lock_getobj(lt, obj, ndx, create, retp)
DB_LOCKREGION *region;
int ret;
void *p;
+ u_int32_t len;
dbenv = lt->dbenv;
region = lt->reginfo.primary;
+ len = 0;
/* Look up the object in the hash table. */
- SH_TAILQ_FOREACH(sh_obj, &lt->obj_tab[ndx], links, __db_lockobj)
+ SH_TAILQ_FOREACH(sh_obj, &lt->obj_tab[ndx], links, __db_lockobj) {
+ len++;
if (obj->size == sh_obj->lockobj.size &&
memcmp(obj->data,
SH_DBT_PTR(&sh_obj->lockobj), obj->size) == 0)
break;
+ }
+
+ if (len > lt->obj_stat[ndx].st_hash_len)
+ lt->obj_stat[ndx].st_hash_len = len;
/*
* If we found the object, then we can just return it. If
* we didn't find the object, then we need to create it.
*/
if (sh_obj == NULL && create) {
+ LOCK_OBJECTS(dbenv, region);
/* Create new object and then insert it into hash table. */
if ((sh_obj =
SH_TAILQ_FIRST(&region->free_objs, __db_lockobj)) == NULL) {
+ UNLOCK_OBJECTS(dbenv, region);
ret = __lock_nomem(lt->dbenv, "object entries");
goto err;
}
/*
* If we can fit this object in the structure, do so instead
- * of shalloc-ing space for it.
+ * of alloc-ing space for it.
*/
if (obj->size <= sizeof(sh_obj->objdata))
p = sh_obj->objdata;
else if ((ret =
- __db_shalloc(&lt->reginfo, obj->size, 0, &p)) != 0) {
+ __env_alloc(&lt->reginfo, obj->size, &p)) != 0) {
+ UNLOCK_OBJECTS(dbenv, region);
__db_errx(dbenv, "No space for lock object storage");
goto err;
}
@@ -1264,9 +1341,13 @@ __lock_getobj(lt, obj, ndx, create, retp)
SH_TAILQ_REMOVE(
&region->free_objs, sh_obj, links, __db_lockobj);
+#ifdef HAVE_STATISTICS
if (++region->stat.st_nobjects > region->stat.st_maxnobjects)
region->stat.st_maxnobjects = region->stat.st_nobjects;
+#endif
+ UNLOCK_OBJECTS(dbenv, region);
+ sh_obj->indx = ndx;
SH_TAILQ_INIT(&sh_obj->waiters);
SH_TAILQ_INIT(&sh_obj->holders);
sh_obj->lockobj.size = obj->size;
@@ -1290,18 +1371,18 @@ err: return (ret);
* the lock is already held by an ancestor.
*/
static int
-__lock_is_parent(lt, locker, sh_locker)
+__lock_is_parent(lt, l_off, sh_locker)
DB_LOCKTAB *lt;
- u_int32_t locker;
+ roff_t l_off;
DB_LOCKER *sh_locker;
{
DB_LOCKER *parent;
parent = sh_locker;
while (parent->parent_locker != INVALID_ROFF) {
- parent = R_ADDR(&lt->reginfo, parent->parent_locker);
- if (parent->id == locker)
+ if (parent->parent_locker == l_off)
return (1);
+ parent = R_ADDR(&lt->reginfo, parent->parent_locker);
}
return (0);
@@ -1313,38 +1394,28 @@ __lock_is_parent(lt, locker, sh_locker)
* *retp == 1 if so, 0 otherwise.
*
* PUBLIC: int __lock_locker_is_parent
- * PUBLIC: __P((DB_ENV *, u_int32_t, u_int32_t, int *));
+ * PUBLIC: __P((DB_ENV *, DB_LOCKER *, DB_LOCKER *, int *));
*/
int
__lock_locker_is_parent(dbenv, locker, child, retp)
DB_ENV *dbenv;
- u_int32_t locker, child;
+ DB_LOCKER *locker;
+ DB_LOCKER *child;
int *retp;
{
- DB_LOCKER *sh_locker;
- DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- u_int32_t locker_ndx;
- int ret;
lt = dbenv->lk_handle;
- region = lt->reginfo.primary;
-
- LOCKER_LOCK(lt, region, child, locker_ndx);
- if ((ret =
- __lock_getlocker(lt, child, locker_ndx, 0, &sh_locker)) != 0) {
- __db_errx(dbenv, __db_locker_invalid);
- return (ret);
- }
/*
* The locker may not exist for this transaction, if not then it has
* no parents.
*/
- if (sh_locker == NULL)
+ if (locker == NULL)
*retp = 0;
else
- *retp = __lock_is_parent(lt, locker, sh_locker);
+ *retp = __lock_is_parent(lt,
+ R_OFFSET(&lt->reginfo, locker), child);
return (0);
}
@@ -1353,20 +1424,18 @@ __lock_locker_is_parent(dbenv, locker, child, retp)
* Called on child commit to merge child's locks with parent's.
*/
static int
-__lock_inherit_locks(lt, locker, flags)
+__lock_inherit_locks(lt, sh_locker, flags)
DB_LOCKTAB *lt;
- u_int32_t locker;
+ DB_LOCKER *sh_locker;
u_int32_t flags;
{
DB_ENV *dbenv;
- DB_LOCKER *sh_locker, *sh_parent;
+ DB_LOCKER *sh_parent;
DB_LOCKOBJ *obj;
- DB_LOCKREGION *region;
int ret;
struct __db_lock *hlp, *lp;
- u_int32_t ndx;
+ roff_t poff;
- region = lt->reginfo.primary;
dbenv = lt->dbenv;
/*
@@ -1377,15 +1446,10 @@ __lock_inherit_locks(lt, locker, flags)
* exist, that just means that the child holds no
* locks, so inheritance is easy!
*/
- LOCKER_LOCK(lt, region, locker, ndx);
- if ((ret = __lock_getlocker(lt,
- locker, ndx, 0, &sh_locker)) != 0 ||
- sh_locker == NULL ||
+ if (sh_locker == NULL ||
F_ISSET(sh_locker, DB_LOCKER_DELETED)) {
- if (ret == 0 && sh_locker != NULL)
- ret = EINVAL;
__db_errx(dbenv, __db_locker_invalid);
- return (ret);
+ return (EINVAL);
}
/* Make sure we are a child transaction. */
@@ -1400,14 +1464,9 @@ __lock_inherit_locks(lt, locker, flags)
* Now, lock the parent locker; move locks from
* the committing list to the parent's list.
*/
- LOCKER_LOCK(lt, region, locker, ndx);
if (F_ISSET(sh_parent, DB_LOCKER_DELETED)) {
- if (ret == 0) {
- __db_errx(dbenv,
- "Parent locker is not valid");
- ret = EINVAL;
- }
- return (ret);
+ __db_errx(dbenv, "Parent locker is not valid");
+ return (EINVAL);
}
/*
@@ -1416,6 +1475,7 @@ __lock_inherit_locks(lt, locker, flags)
* not require an inordinate number of locks, we try
* to merge the child's locks with its parent's.
*/
+ poff = R_OFFSET(&lt->reginfo, sh_parent);
for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
lp != NULL;
lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
@@ -1424,8 +1484,7 @@ __lock_inherit_locks(lt, locker, flags)
/* See if the parent already has a lock. */
obj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
SH_TAILQ_FOREACH(hlp, &obj->holders, links, __db_lock)
- if (hlp->holder == sh_parent->id &&
- lp->mode == hlp->mode)
+ if (hlp->holder == poff && lp->mode == hlp->mode)
break;
if (hlp != NULL) {
@@ -1435,12 +1494,12 @@ __lock_inherit_locks(lt, locker, flags)
/* Remove lock from object list and free it. */
DB_ASSERT(dbenv, lp->status == DB_LSTAT_HELD);
SH_TAILQ_REMOVE(&obj->holders, lp, links, __db_lock);
- (void)__lock_freelock(lt, lp, locker, DB_LOCK_FREE);
+ (void)__lock_freelock(lt, lp, sh_locker, DB_LOCK_FREE);
} else {
/* Just move lock to parent chains. */
SH_LIST_INSERT_HEAD(&sh_parent->heldby,
lp, locker_links, __db_lock);
- lp->holder = sh_parent->id;
+ lp->holder = poff;
}
/*
@@ -1458,7 +1517,7 @@ __lock_inherit_locks(lt, locker, flags)
sh_parent->nlocks += sh_locker->nlocks;
sh_parent->nwrites += sh_locker->nwrites;
- return (ret);
+ return (0);
}
/*
@@ -1478,9 +1537,7 @@ __lock_promote(lt, obj, state_changedp, flags)
u_int32_t flags;
{
struct __db_lock *lp_w, *lp_h, *next_waiter;
- DB_LOCKER *sh_locker;
DB_LOCKREGION *region;
- u_int32_t locker_ndx;
int had_waiters, state_changed;
region = lt->reginfo.primary;
@@ -1516,17 +1573,8 @@ __lock_promote(lt, obj, state_changedp, flags)
SH_TAILQ_FOREACH(lp_h, &obj->holders, links, __db_lock) {
if (lp_h->holder != lp_w->holder &&
CONFLICTS(lt, region, lp_h->mode, lp_w->mode)) {
- LOCKER_LOCK(lt,
- region, lp_w->holder, locker_ndx);
- if ((__lock_getlocker(lt, lp_w->holder,
- locker_ndx, 0, &sh_locker)) != 0) {
- __db_errx(lt->dbenv,
- "Locker %#lx missing",
- (u_long)lp_w->holder);
- return (__db_panic(lt->dbenv, EINVAL));
- }
- if (!__lock_is_parent(lt,
- lp_h->holder, sh_locker))
+ if (!__lock_is_parent(lt, lp_h->holder,
+ R_ADDR(&lt->reginfo, lp_w->holder)))
break;
}
}
@@ -1547,8 +1595,16 @@ __lock_promote(lt, obj, state_changedp, flags)
* If this object had waiters and doesn't any more, then we need
* to remove it from the dd_obj list.
*/
- if (had_waiters && SH_TAILQ_FIRST(&obj->waiters, __db_lock) == NULL)
+ if (had_waiters && SH_TAILQ_FIRST(&obj->waiters, __db_lock) == NULL) {
+ LOCK_OBJECTS(lt->dbenv, region);
+ /*
+ * Bump the generation when removing an object from the
+ * queue so that the deadlock detector will retry.
+ */
+ obj->generation++;
SH_TAILQ_REMOVE(&region->dd_objs, obj, dd_links, __db_lockobj);
+ UNLOCK_OBJECTS(lt->dbenv, region);
+ }
if (state_changedp != NULL)
*state_changedp = state_changed;
@@ -1583,10 +1639,14 @@ __lock_remove_waiter(lt, sh_obj, lockp, status)
SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);
lockp->links.stqe_prev = -1;
lockp->status = status;
- if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)
+ if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) {
+ LOCK_OBJECTS(lt->dbenv, region);
+ sh_obj->generation++;
SH_TAILQ_REMOVE(
&region->dd_objs,
sh_obj, dd_links, __db_lockobj);
+ UNLOCK_OBJECTS(lt->dbenv, region);
+ }
/*
* Wake whoever is waiting on this lock.
@@ -1608,44 +1668,35 @@ static int
__lock_trade(dbenv, lock, new_locker)
DB_ENV *dbenv;
DB_LOCK *lock;
- u_int32_t new_locker;
+ DB_LOCKER *new_locker;
{
struct __db_lock *lp;
- DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- DB_LOCKER *sh_locker;
int ret;
- u_int32_t locker_ndx;
lt = dbenv->lk_handle;
- region = lt->reginfo.primary;
lp = R_ADDR(&lt->reginfo, lock->off);
/* If the lock is already released, simply return. */
if (lp->gen != lock->gen)
return (DB_NOTFOUND);
- /* Make sure that we can get new locker and add this lock to it. */
- LOCKER_LOCK(lt, region, new_locker, locker_ndx);
- if ((ret =
- __lock_getlocker(lt, new_locker, locker_ndx, 0, &sh_locker)) != 0)
- return (ret);
-
- if (sh_locker == NULL) {
+ if (new_locker == NULL) {
__db_errx(dbenv, "Locker does not exist");
return (EINVAL);
}
/* Remove the lock from its current locker. */
- if ((ret = __lock_freelock(lt, lp, lp->holder, DB_LOCK_UNLINK)) != 0)
+ if ((ret = __lock_freelock(lt,
+ lp, R_ADDR(&lt->reginfo, lp->holder), DB_LOCK_UNLINK)) != 0)
return (ret);
/* Add lock to its new locker. */
- SH_LIST_INSERT_HEAD(&sh_locker->heldby, lp, locker_links, __db_lock);
- sh_locker->nlocks++;
+ SH_LIST_INSERT_HEAD(&new_locker->heldby, lp, locker_links, __db_lock);
+ new_locker->nlocks++;
if (IS_WRITELOCK(lp->mode))
- sh_locker->nwrites++;
- lp->holder = new_locker;
+ new_locker->nwrites++;
+ lp->holder = R_OFFSET(&lt->reginfo, new_locker);
return (0);
}
diff --git a/db/lock/lock_conflict.c b/db/lock/lock_conflict.c
deleted file mode 100644
index 2d7945fe2..000000000
--- a/db/lock/lock_conflict.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 1996, 1997, 1998, 1999, 2000
- * Sleepycat Software. All rights reserved.
- */
-
-#include "db_config.h"
-
-#ifndef lint
-static const char revid[] = "$Id: lock_conflict.c,v 11.6 2000/12/12 17:38:13 bostic Exp $";
-#endif /* not lint */
-
-#ifndef NO_SYSTEM_INCLUDES
-#include <sys/types.h>
-#endif
-
-#include "db_int.h"
-
-/*
- * The conflict arrays are set up such that the row is the lock you
- * are holding and the column is the lock that is desired.
- */
-
-const u_int8_t db_riw_conflicts[] = {
- /* N S X WT IX IS SIX */
- /* N */ 0, 0, 0, 0, 0, 0, 0,
- /* S */ 0, 0, 1, 0, 1, 0, 1,
- /* X */ 0, 1, 1, 1, 1, 1, 1,
- /* WT */ 0, 0, 0, 0, 0, 0, 0,
- /* IX */ 0, 1, 1, 0, 0, 0, 0,
- /* IS */ 0, 0, 1, 0, 0, 0, 0,
- /* SIX */ 0, 1, 1, 0, 0, 0, 0
-};
diff --git a/db/lock/lock_deadlock.c b/db/lock/lock_deadlock.c
index 4dfcfc727..ed0644676 100644
--- a/db/lock/lock_deadlock.c
+++ b/db/lock/lock_deadlock.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_deadlock.c,v 12.17 2006/08/24 14:46:10 bostic Exp $
+ * $Id: lock_deadlock.c,v 12.26 2007/05/17 19:33:04 bostic Exp $
*/
#include "db_config.h"
@@ -40,13 +39,14 @@ typedef struct {
u_int32_t id;
roff_t last_lock;
roff_t last_obj;
+ u_int32_t last_ndx;
u_int32_t last_locker_id;
db_pgno_t pgno;
} locker_info;
static int __dd_abort __P((DB_ENV *, locker_info *, int *));
-static int __dd_build __P((DB_ENV *,
- u_int32_t, u_int32_t **, u_int32_t *, u_int32_t *, locker_info **));
+static int __dd_build __P((DB_ENV *, u_int32_t,
+ u_int32_t **, u_int32_t *, u_int32_t *, locker_info **, int*));
static int __dd_find __P((DB_ENV *,
u_int32_t *, locker_info *, u_int32_t, u_int32_t, u_int32_t ***));
static int __dd_isolder __P((u_int32_t, u_int32_t, u_int32_t, u_int32_t));
@@ -65,10 +65,10 @@ static void __dd_debug
* PUBLIC: int __lock_detect_pp __P((DB_ENV *, u_int32_t, u_int32_t, int *));
*/
int
-__lock_detect_pp(dbenv, flags, atype, abortp)
+__lock_detect_pp(dbenv, flags, atype, rejectp)
DB_ENV *dbenv;
u_int32_t flags, atype;
- int *abortp;
+ int *rejectp;
{
DB_THREAD_INFO *ip;
int ret;
@@ -98,7 +98,7 @@ __lock_detect_pp(dbenv, flags, atype, abortp)
}
ENV_ENTER(dbenv, ip);
- REPLICATION_WRAP(dbenv, (__lock_detect(dbenv, atype, abortp)), ret);
+ REPLICATION_WRAP(dbenv, (__lock_detect(dbenv, atype, rejectp)), ret);
ENV_LEAVE(dbenv, ip);
return (ret);
}
@@ -110,14 +110,14 @@ __lock_detect_pp(dbenv, flags, atype, abortp)
* PUBLIC: int __lock_detect __P((DB_ENV *, u_int32_t, int *));
*/
int
-__lock_detect(dbenv, atype, abortp)
+__lock_detect(dbenv, atype, rejectp)
DB_ENV *dbenv;
u_int32_t atype;
- int *abortp;
+ int *rejectp;
{
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- db_timeval_t now;
+ db_timespec now;
locker_info *idmap;
u_int32_t *bitmap, *copymap, **deadp, **free_me, *tmpmap;
u_int32_t i, cid, keeper, killid, limit, nalloc, nlockers;
@@ -134,8 +134,8 @@ __lock_detect(dbenv, atype, abortp)
free_me = NULL;
lt = dbenv->lk_handle;
- if (abortp != NULL)
- *abortp = 0;
+ if (rejectp != NULL)
+ *rejectp = 0;
/* Check if a detector run is necessary. */
LOCK_SYSTEM_LOCK(dbenv);
@@ -143,9 +143,9 @@ __lock_detect(dbenv, atype, abortp)
/* Make a pass only if auto-detect would run. */
region = lt->reginfo.primary;
- LOCK_SET_TIME_INVALID(&now);
+ timespecclear(&now);
if (region->need_dd == 0 &&
- (!LOCK_TIME_ISVALID(&region->next_timeout) ||
+ (!timespecisset(&region->next_timeout) ||
!__lock_expired(dbenv, &now, &region->next_timeout))) {
LOCK_SYSTEM_UNLOCK(dbenv);
return (0);
@@ -157,7 +157,8 @@ __lock_detect(dbenv, atype, abortp)
region->need_dd = 0;
/* Build the waits-for bitmap. */
- ret = __dd_build(dbenv, atype, &bitmap, &nlockers, &nalloc, &idmap);
+ ret = __dd_build(dbenv,
+ atype, &bitmap, &nlockers, &nalloc, &idmap, rejectp);
lock_max = region->stat.st_cur_maxid;
LOCK_SYSTEM_UNLOCK(dbenv);
if (ret != 0 || atype == DB_LOCK_EXPIRE)
@@ -206,8 +207,8 @@ __lock_detect(dbenv, atype, abortp)
killid = BAD_KILLID;
free_me = deadp;
for (; *deadp != NULL; deadp++) {
- if (abortp != NULL)
- ++*abortp;
+ if (rejectp != NULL)
+ ++*rejectp;
killid = (u_int32_t)(*deadp - bitmap) / nalloc;
limit = killid;
@@ -363,26 +364,29 @@ err: if (free_me != NULL)
#define DD_INVALID_ID ((u_int32_t) -1)
static int
-__dd_build(dbenv, atype, bmp, nlockers, allocp, idmap)
+__dd_build(dbenv, atype, bmp, nlockers, allocp, idmap, rejectp)
DB_ENV *dbenv;
u_int32_t atype, **bmp, *nlockers, *allocp;
locker_info **idmap;
+ int *rejectp;
{
struct __db_lock *lp;
DB_LOCKER *lip, *lockerp, *child;
- DB_LOCKOBJ *op, *lo;
+ DB_LOCKOBJ *op, *lo, *np;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
locker_info *id_array;
- db_timeval_t now, min_timeout;
- u_int32_t *bitmap, count, dd, *entryp, id, ndx, nentries, *tmpmap;
+ db_timespec now, min_timeout;
+ u_int32_t *bitmap, count, dd;
+ u_int32_t *entryp, gen, id, indx, ndx, nentries, *tmpmap;
u_int8_t *pptr;
int is_first, ret;
+ COMPQUIET(indx, 0);
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
- LOCK_SET_TIME_INVALID(&now);
- LOCK_SET_TIME_MAX(&min_timeout);
+ timespecclear(&now);
+ timespecclear(&min_timeout);
/*
* While we always check for expired timeouts, if we are called with
@@ -393,26 +397,42 @@ __dd_build(dbenv, atype, bmp, nlockers, allocp, idmap)
* needs to expect this.
*/
if (atype == DB_LOCK_EXPIRE) {
- SH_TAILQ_FOREACH(op, &region->dd_objs, dd_links, __db_lockobj)
+skip: LOCK_OBJECTS(dbenv, region);
+ op = SH_TAILQ_FIRST(&region->dd_objs, __db_lockobj);
+ for (; op != NULL; op = np) {
+ indx = op->indx;
+ gen = op->generation;
+ UNLOCK_OBJECTS(dbenv, region);
+ OBJECT_LOCK_NDX(lt, indx);
+ if (op->generation != gen) {
+ OBJECT_UNLOCK(lt, indx);
+ goto skip;
+ }
SH_TAILQ_FOREACH(lp, &op->waiters, links, __db_lock) {
- LOCKER_LOCK(lt, region, lp->holder, ndx);
- if ((ret = __lock_getlocker(lt,
- lp->holder, ndx, 0, &lockerp)) != 0)
- continue;
+ lockerp = (DB_LOCKER *)
+ R_ADDR(&lt->reginfo, lp->holder);
if (lp->status == DB_LSTAT_WAITING) {
if (__lock_expired(dbenv,
&now, &lockerp->lk_expire)) {
lp->status = DB_LSTAT_EXPIRED;
MUTEX_UNLOCK(
dbenv, lp->mtx_lock);
+ if (rejectp != NULL)
+ ++*rejectp;
continue;
}
- if (LOCK_TIME_GREATER(
- &min_timeout, &lockerp->lk_expire))
+ if (!timespecisset(&min_timeout) ||
+ timespeccmp(&min_timeout,
+ &lockerp->lk_expire, >))
min_timeout =
lockerp->lk_expire;
}
}
+ LOCK_OBJECTS(dbenv, region);
+ np = SH_TAILQ_NEXT(op, dd_links, __db_lockobj);
+ OBJECT_UNLOCK(lt, indx);
+ }
+ UNLOCK_OBJECTS(dbenv, region);
goto done;
}
@@ -472,6 +492,7 @@ retry: count = region->stat.st_nlockers;
* First we go through and assign each locker a deadlock detector id.
*/
id = 0;
+ LOCK_LOCKERS(dbenv, region);
SH_TAILQ_FOREACH(lip, &region->lockers, ulinks, __db_locker) {
if (lip->master_locker == INVALID_ROFF) {
lip->dd_id = id++;
@@ -494,30 +515,55 @@ retry: count = region->stat.st_nlockers;
lip->dd_id = DD_INVALID_ID;
}
+ UNLOCK_LOCKERS(dbenv, region);
/*
* We only need consider objects that have waiters, so we use
* the list of objects with waiters (dd_objs) instead of traversing
* the entire hash table. For each object, we traverse the waiters
* list and add an entry in the waitsfor matrix for each waiter/holder
- * combination.
+ * combination. We don't want to lock from the OBJECTS mutex to the
+ * hash mutex, so we drop objects and get the hash mutex. Then
+ * check to see if the object has changed. Once we have the object
+ * locked then locks cannot be remove and lockers cannot go away.
*/
- SH_TAILQ_FOREACH(op, &region->dd_objs, dd_links, __db_lockobj) {
- CLEAR_MAP(tmpmap, nentries);
+ if (0) {
+ /* If an object has changed state, start over. */
+again: memset(bitmap, 0, count * sizeof(u_int32_t) * nentries);
+ }
+ LOCK_OBJECTS(dbenv, region);
+ op = SH_TAILQ_FIRST(&region->dd_objs, __db_lockobj);
+ for (; op != NULL; op = np) {
+ indx = op->indx;
+ gen = op->generation;
+ UNLOCK_OBJECTS(dbenv, region);
+
+ OBJECT_LOCK_NDX(lt, indx);
+ if (gen != op->generation) {
+ OBJECT_UNLOCK(lt, indx);
+ goto again;
+ }
/*
* First we go through and create a bit map that
* represents all the holders of this object.
*/
+
+ CLEAR_MAP(tmpmap, nentries);
SH_TAILQ_FOREACH(lp, &op->holders, links, __db_lock) {
- LOCKER_LOCK(lt, region, lp->holder, ndx);
- if ((ret = __lock_getlocker(lt,
- lp->holder, ndx, 0, &lockerp)) != 0)
- continue;
+ lockerp = (DB_LOCKER *)R_ADDR(&lt->reginfo, lp->holder);
if (lockerp->dd_id == DD_INVALID_ID) {
+ /*
+ * If the locker was not here when we started,
+ * then it was not deadlocked at that time.
+ */
+ if (lockerp->master_locker == INVALID_ROFF)
+ continue;
dd = ((DB_LOCKER *)R_ADDR(&lt->reginfo,
lockerp->master_locker))->dd_id;
+ if (dd == DD_INVALID_ID)
+ continue;
lockerp->dd_id = dd;
switch (atype) {
case DB_LOCK_MINLOCKS:
@@ -555,19 +601,19 @@ retry: count = region->stat.st_nlockers;
lp != NULL;
is_first = 0,
lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
- LOCKER_LOCK(lt, region, lp->holder, ndx);
- if ((ret = __lock_getlocker(lt,
- lp->holder, ndx, 0, &lockerp)) != 0)
- continue;
+ lockerp = (DB_LOCKER *)R_ADDR(&lt->reginfo, lp->holder);
if (lp->status == DB_LSTAT_WAITING) {
if (__lock_expired(dbenv,
&now, &lockerp->lk_expire)) {
lp->status = DB_LSTAT_EXPIRED;
MUTEX_UNLOCK(dbenv, lp->mtx_lock);
+ if (rejectp != NULL)
+ ++*rejectp;
continue;
}
- if (LOCK_TIME_GREATER(
- &min_timeout, &lockerp->lk_expire))
+ if (!timespecisset(&min_timeout) ||
+ timespeccmp(
+ &min_timeout, &lockerp->lk_expire, >))
min_timeout = lockerp->lk_expire;
}
@@ -613,19 +659,28 @@ retry: count = region->stat.st_nlockers;
CLR_MAP(entryp, dd);
}
}
+ LOCK_OBJECTS(dbenv, region);
+ np = SH_TAILQ_NEXT(op, dd_links, __db_lockobj);
+ OBJECT_UNLOCK(lt, indx);
}
+ UNLOCK_OBJECTS(dbenv, region);
- /* Now for each locker; record its last lock. */
+ /*
+ * Now for each locker, record its last lock.
+ * We need to look at the heldby list carefully. We have the LOCKERS
+ * locked so they cannot go away. The lock at the head of the
+ * list can be removed by locking the object it points at.
+ * Since lock memory is not freed if we get a lock we can look
+ * at it safely but SH_LIST_FIRST is not atomic, so we check that
+ * the list has not gone empty during that macro.
+ */
+ LOCK_LOCKERS(dbenv, region);
for (id = 0; id < count; id++) {
if (!id_array[id].valid)
continue;
- LOCKER_LOCK(lt, region, id_array[id].id, ndx);
- if ((ret = __lock_getlocker(lt,
- id_array[id].id, ndx, 0, &lockerp)) != 0) {
- __db_errx(dbenv,
- "No locks for locker %lu", (u_long)id_array[id].id);
+ if ((ret = __lock_getlocker_int(lt,
+ id_array[id].id, 0, &lockerp)) != 0 || lockerp == NULL)
continue;
- }
/*
* If this is a master transaction, try to
@@ -635,35 +690,55 @@ retry: count = region->stat.st_nlockers;
child = SH_LIST_FIRST(&lockerp->child_locker, __db_locker);
if (child != NULL) {
do {
- lp = SH_LIST_FIRST(&child->heldby, __db_lock);
+c_retry: lp = SH_LIST_FIRST(&child->heldby, __db_lock);
+ if (SH_LIST_EMPTY(&child->heldby) || lp == NULL)
+ goto c_next;
+
+ ndx = lp->indx;
+ OBJECT_LOCK_NDX(lt, ndx);
+ if (lp != SH_LIST_FIRST(
+ &child->heldby, __db_lock) ||
+ ndx != lp->indx) {
+ OBJECT_UNLOCK(lt, ndx);
+ goto c_retry;
+ }
+
if (lp != NULL &&
lp->status == DB_LSTAT_WAITING) {
id_array[id].last_locker_id = child->id;
goto get_lock;
+ } else {
+ OBJECT_UNLOCK(lt, ndx);
}
- child = SH_LIST_NEXT(
+c_next: child = SH_LIST_NEXT(
child, child_link, __db_locker);
} while (child != NULL);
}
- lp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
- if (lp != NULL) {
+
+l_retry: lp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
+ if (!SH_LIST_EMPTY(&lockerp->heldby) && lp != NULL) {
+ ndx = lp->indx;
+ OBJECT_LOCK_NDX(lt, ndx);
+ if (lp != SH_LIST_FIRST(&lockerp->heldby, __db_lock) ||
+ lp->indx != ndx) {
+ OBJECT_UNLOCK(lt, ndx);
+ goto l_retry;
+ }
id_array[id].last_locker_id = lockerp->id;
get_lock: id_array[id].last_lock = R_OFFSET(&lt->reginfo, lp);
id_array[id].last_obj = lp->obj;
lo = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
+ id_array[id].last_ndx = lo->indx;
pptr = SH_DBT_PTR(&lo->lockobj);
if (lo->lockobj.size >= sizeof(db_pgno_t))
memcpy(&id_array[id].pgno,
pptr, sizeof(db_pgno_t));
else
id_array[id].pgno = 0;
+ OBJECT_UNLOCK(lt, ndx);
}
}
-
- /*
- * Pass complete, reset the deadlock detector bit.
- */
- region->need_dd = 0;
+ UNLOCK_LOCKERS(dbenv, region);
/*
* Now we can release everything except the bitmap matrix that we
@@ -674,12 +749,8 @@ get_lock: id_array[id].last_lock = R_OFFSET(&lt->reginfo, lp);
*bmp = bitmap;
*allocp = nentries;
__os_free(dbenv, tmpmap);
-done: if (LOCK_TIME_ISVALID(&region->next_timeout)) {
- if (LOCK_TIME_ISMAX(&min_timeout))
- LOCK_SET_TIME_INVALID(&region->next_timeout);
- else
- region->next_timeout = min_timeout;
- }
+done: if (timespecisset(&region->next_timeout))
+ region->next_timeout = min_timeout;
return (0);
}
@@ -760,7 +831,6 @@ __dd_abort(dbenv, info, statusp)
DB_LOCKOBJ *sh_obj;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- u_int32_t ndx;
int ret;
*statusp = 0;
@@ -769,15 +839,16 @@ __dd_abort(dbenv, info, statusp)
region = lt->reginfo.primary;
ret = 0;
+ /* We must lock so this locker cannot go away while we abort it. */
LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
/*
* Get the locker. If it's gone or was aborted while we were
* detecting, return that.
*/
- LOCKER_LOCK(lt, region, info->last_locker_id, ndx);
- if ((ret = __lock_getlocker(lt,
- info->last_locker_id, ndx, 0, &lockerp)) != 0)
+ if ((ret = __lock_getlocker_int(lt,
+ info->last_locker_id, 0, &lockerp)) != 0)
goto err;
if (lockerp == NULL || F_ISSET(lockerp, DB_LOCKER_INABORT)) {
*statusp = DB_ALREADY_ABORTED;
@@ -787,22 +858,24 @@ __dd_abort(dbenv, info, statusp)
/*
* Find the locker's last lock. It is possible for this lock to have
* been freed, either though a timeout or another detector run.
+ * First lock the lock object so it is stable.
*/
+
+ OBJECT_LOCK_NDX(lt, info->last_ndx);
if ((lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock)) == NULL) {
*statusp = DB_ALREADY_ABORTED;
- goto out;
+ goto done;
}
if (R_OFFSET(&lt->reginfo, lockp) != info->last_lock ||
- lockp->holder != lockerp->id ||
+ lockp->holder != R_OFFSET(&lt->reginfo, lockerp) ||
lockp->obj != info->last_obj || lockp->status != DB_LSTAT_WAITING) {
*statusp = DB_ALREADY_ABORTED;
- goto out;
+ goto done;
}
sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
/* Abort lock, take it off list, and wake up this lock. */
- SHOBJECT_LOCK(lt, region, sh_obj, ndx);
lockp->status = DB_LSTAT_ABORTED;
SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);
@@ -811,16 +884,20 @@ __dd_abort(dbenv, info, statusp)
* it from dd_objs, or it is not empty, in which case we need to
* do promotion.
*/
- if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)
+ if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) {
+ LOCK_OBJECTS(dbenv, region);
SH_TAILQ_REMOVE(&region->dd_objs,
sh_obj, dd_links, __db_lockobj);
- else
+ UNLOCK_OBJECTS(dbenv, region);
+ } else
ret = __lock_promote(lt, sh_obj, NULL, 0);
MUTEX_UNLOCK(dbenv, lockp->mtx_lock);
- region->stat.st_ndeadlocks++;
+ STAT(region->stat.st_ndeadlocks++);
+done: OBJECT_UNLOCK(lt, info->last_ndx);
err:
out: LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, region);
return (ret);
}
diff --git a/db/lock/lock_failchk.c b/db/lock/lock_failchk.c
index 55f729694..c7172daca 100644
--- a/db/lock/lock_failchk.c
+++ b/db/lock/lock_failchk.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2005-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 2005,2007 Oracle. All rights reserved.
*
- * $Id: lock_failchk.c,v 12.9 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_failchk.c,v 12.13 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"
@@ -35,6 +34,7 @@ __lock_failchk(dbenv)
lrp = lt->reginfo.primary;
retry: LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, lrp);
ret = 0;
for (i = 0; i < lrp->locker_t_size; i++)
@@ -71,10 +71,11 @@ retry: LOCK_SYSTEM_LOCK(dbenv);
(u_long)lip->id, dbenv->thread_id_string(
dbenv, lip->pid, lip->tid, buf));
LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, lrp);
memset(&request, 0, sizeof(request));
request.op = DB_LOCK_PUT_ALL;
- if ((ret = __lock_vec(
- dbenv, lip->id, 0, &request, 1, NULL)) != 0)
+ if ((ret = __lock_vec(dbenv,
+ lip, 0, &request, 1, NULL)) != 0)
return (ret);
/*
@@ -84,12 +85,13 @@ retry: LOCK_SYSTEM_LOCK(dbenv);
* but we assume the dead thread will never release
* it.
*/
- if ((ret = __lock_freefamilylocker(lt, lip->id)) != 0)
+ if ((ret = __lock_freefamilylocker(lt, lip)) != 0)
return (ret);
goto retry;
}
LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, lrp);
return (ret);
}
diff --git a/db/lock/lock_id.c b/db/lock/lock_id.c
index 0e9fb14dd..4ae36d5ac 100644
--- a/db/lock/lock_id.c
+++ b/db/lock/lock_id.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_id.c,v 12.16 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_id.c,v 12.24 2007/05/17 17:18:00 bostic Exp $
*/
#include "db_config.h"
@@ -52,7 +51,7 @@ __lock_id(dbenv, idp, lkp)
DB_LOCKER *lk;
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
- u_int32_t id, *ids, locker_ndx;
+ u_int32_t id, *ids;
int nids, ret;
lt = dbenv->lk_handle;
@@ -72,6 +71,8 @@ __lock_id(dbenv, idp, lkp)
* Our current valid range can span the maximum valid value, so check
* for it and wrap manually.
*/
+ LOCK_LOCKERS(dbenv, region);
+
if (region->stat.st_id == DB_LOCK_MAXID &&
region->stat.st_cur_maxid != DB_LOCK_MAXID)
region->stat.st_id = DB_LOCK_INVALIDID;
@@ -92,10 +93,10 @@ __lock_id(dbenv, idp, lkp)
id = ++region->stat.st_id;
/* Allocate a locker for this id. */
- LOCKER_LOCK(lt, region, id, locker_ndx);
- ret = __lock_getlocker(lt, id, locker_ndx, 1, &lk);
+ ret = __lock_getlocker_int(lt, id, 1, &lk);
err: LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, region);
if (idp)
*idp = id;
@@ -107,14 +108,17 @@ err: LOCK_SYSTEM_UNLOCK(dbenv);
/*
* __lock_set_thread_id --
* Set the thread_id in an existing locker.
- * PUBLIC: void __lock_set_thread_id __P((DB_LOCKER *, pid_t, db_threadid_t));
+ * PUBLIC: void __lock_set_thread_id __P((void *, pid_t, db_threadid_t));
*/
void
-__lock_set_thread_id(lref, pid, tid)
- DB_LOCKER *lref;
+__lock_set_thread_id(lref_arg, pid, tid)
+ void *lref_arg;
pid_t pid;
db_threadid_t tid;
{
+ DB_LOCKER *lref;
+
+ lref = lref_arg;
lref->pid = pid;
lref->tid = tid;
}
@@ -130,16 +134,38 @@ __lock_id_free_pp(dbenv, id)
DB_ENV *dbenv;
u_int32_t id;
{
+ DB_LOCKER *sh_locker;
+ DB_LOCKREGION *region;
+ DB_LOCKTAB *lt;
DB_THREAD_INFO *ip;
- int ret;
+ int handle_check, ret, t_ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lk_handle, "DB_ENV->lock_id_free", DB_INIT_LOCK);
ENV_ENTER(dbenv, ip);
- REPLICATION_WRAP(dbenv, (__lock_id_free(dbenv, id)), ret);
- ENV_LEAVE(dbenv, ip);
+ /* Check for replication block. */
+ handle_check = IS_ENV_REPLICATED(dbenv);
+ if (handle_check && (ret = __env_rep_enter(dbenv, 1)) != 0) {
+ handle_check = 0;
+ goto err;
+ }
+
+ lt = dbenv->lk_handle;
+ region = lt->reginfo.primary;
+
+ LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
+ if ((ret =
+ __lock_getlocker_int(dbenv->lk_handle, id, 0, &sh_locker)) == 0)
+ ret = __lock_freelocker(lt, region, sh_locker);
+ UNLOCK_LOCKERS(dbenv, region);
+ LOCK_SYSTEM_UNLOCK(dbenv);
+
+ if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
+ ret = t_ret;
+err: ENV_LEAVE(dbenv, ip);
return (ret);
}
@@ -147,36 +173,20 @@ __lock_id_free_pp(dbenv, id)
* __lock_id_free --
* Free a locker id.
*
- * PUBLIC: int __lock_id_free __P((DB_ENV *, u_int32_t));
+ * PUBLIC: int __lock_id_free __P((DB_ENV *, DB_LOCKER *));
*/
int
-__lock_id_free(dbenv, id)
+__lock_id_free(dbenv, sh_locker)
DB_ENV *dbenv;
- u_int32_t id;
-{
DB_LOCKER *sh_locker;
+{
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
- u_int32_t locker_ndx;
int ret;
- PANIC_CHECK(dbenv);
- ENV_REQUIRES_CONFIG(dbenv,
- dbenv->lk_handle, "DB_ENV->lock_id_free", DB_INIT_LOCK);
-
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
-
- LOCK_SYSTEM_LOCK(dbenv);
- LOCKER_LOCK(lt, region, id, locker_ndx);
- if ((ret = __lock_getlocker(lt, id, locker_ndx, 0, &sh_locker)) != 0)
- goto err;
-
- if (sh_locker == NULL) {
- __db_errx(dbenv, "Unknown locker ID: %lx", (u_long)id);
- ret = EINVAL;
- goto err;
- }
+ ret = 0;
if (sh_locker->nlocks != 0) {
__db_errx(dbenv, "Locker still has locks");
@@ -184,9 +194,13 @@ __lock_id_free(dbenv, id)
goto err;
}
- __lock_freelocker(lt, region, sh_locker, locker_ndx);
+ LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
+ ret = __lock_freelocker(lt, region, sh_locker);
+ UNLOCK_LOCKERS(dbenv, region);
+ LOCK_SYSTEM_UNLOCK(dbenv);
-err: LOCK_SYSTEM_UNLOCK(dbenv);
+err:
return (ret);
}
@@ -222,25 +236,54 @@ __lock_id_set(dbenv, cur_id, max_id)
* indicates if the locker should be created if it doesn't exist in
* the table.
*
- * This must be called with the locker bucket locked.
+ * This must be called with the locker mutex lock if create == 1.
*
* PUBLIC: int __lock_getlocker __P((DB_LOCKTAB *,
- * PUBLIC: u_int32_t, u_int32_t, int, DB_LOCKER **));
+ * PUBLIC: u_int32_t, int, DB_LOCKER **));
+ * PUBLIC: int __lock_getlocker_int __P((DB_LOCKTAB *,
+ * PUBLIC: u_int32_t, int, DB_LOCKER **));
*/
int
-__lock_getlocker(lt, locker, indx, create, retp)
+__lock_getlocker(lt, locker, create, retp)
DB_LOCKTAB *lt;
- u_int32_t locker, indx;
+ u_int32_t locker;
+ int create;
+ DB_LOCKER **retp;
+{
+ DB_ENV *dbenv;
+ DB_LOCKREGION *region;
+ int ret;
+
+ COMPQUIET(region, NULL);
+ dbenv = lt->dbenv;
+ region = lt->reginfo.primary;
+
+ LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
+ ret = __lock_getlocker_int(lt, locker, create, retp);
+ UNLOCK_LOCKERS(dbenv, region);
+ LOCK_SYSTEM_UNLOCK(dbenv);
+
+ return (ret);
+}
+
+int
+__lock_getlocker_int(lt, locker, create, retp)
+ DB_LOCKTAB *lt;
+ u_int32_t locker;
int create;
DB_LOCKER **retp;
{
DB_ENV *dbenv;
DB_LOCKER *sh_locker;
DB_LOCKREGION *region;
+ u_int32_t indx;
dbenv = lt->dbenv;
region = lt->reginfo.primary;
+ LOCKER_HASH(lt, region, locker, indx);
+
/*
* If we find the locker, then we can just return it. If we don't find
* the locker, then we need to create it.
@@ -255,8 +298,11 @@ __lock_getlocker(lt, locker, indx, create, retp)
return (__lock_nomem(dbenv, "locker entries"));
SH_TAILQ_REMOVE(
&region->free_lockers, sh_locker, links, __db_locker);
- if (++region->stat.st_nlockers > region->stat.st_maxnlockers)
+ ++region->stat.st_nlockers;
+#ifdef HAVE_STATISTICS
+ if (region->stat.st_nlockers > region->stat.st_maxnlockers)
region->stat.st_maxnlockers = region->stat.st_nlockers;
+#endif
sh_locker->id = locker;
dbenv->thread_id(dbenv, &sh_locker->pid, &sh_locker->tid);
@@ -269,8 +315,8 @@ __lock_getlocker(lt, locker, indx, create, retp)
sh_locker->nlocks = 0;
sh_locker->nwrites = 0;
sh_locker->lk_timeout = 0;
- LOCK_SET_TIME_INVALID(&sh_locker->tx_expire);
- LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);
+ timespecclear(&sh_locker->tx_expire);
+ timespecclear(&sh_locker->lk_expire);
SH_TAILQ_INSERT_HEAD(
&lt->locker_tab[indx], sh_locker, links, __db_locker);
@@ -296,16 +342,16 @@ __lock_addfamilylocker(dbenv, pid, id)
DB_LOCKER *lockerp, *mlockerp;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
- u_int32_t ndx;
int ret;
+ COMPQUIET(region, NULL);
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
/* get/create the parent locker info */
- LOCKER_LOCK(lt, region, pid, ndx);
- if ((ret = __lock_getlocker(lt, pid, ndx, 1, &mlockerp)) != 0)
+ if ((ret = __lock_getlocker_int(lt, pid, 1, &mlockerp)) != 0)
goto err;
/*
@@ -315,8 +361,7 @@ __lock_addfamilylocker(dbenv, pid, id)
* we manipulate it, nor can another child in the
* family be created at the same time.
*/
- LOCKER_LOCK(lt, region, id, ndx);
- if ((ret = __lock_getlocker(lt, id, ndx, 1, &lockerp)) != 0)
+ if ((ret = __lock_getlocker_int(lt, id, 1, &lockerp)) != 0)
goto err;
/* Point to our parent. */
@@ -339,6 +384,7 @@ __lock_addfamilylocker(dbenv, pid, id)
&mlockerp->child_locker, lockerp, child_link, __db_locker);
err: LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, region);
return (ret);
}
@@ -349,28 +395,25 @@ err: LOCK_SYSTEM_UNLOCK(dbenv);
*
* This must be called without the locker bucket locked.
*
- * PUBLIC: int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t));
+ * PUBLIC: int __lock_freefamilylocker __P((DB_LOCKTAB *, DB_LOCKER *));
*/
int
-__lock_freefamilylocker(lt, locker)
+__lock_freefamilylocker(lt, sh_locker)
DB_LOCKTAB *lt;
- u_int32_t locker;
+ DB_LOCKER *sh_locker;
{
DB_ENV *dbenv;
- DB_LOCKER *sh_locker;
DB_LOCKREGION *region;
- u_int32_t indx;
int ret;
dbenv = lt->dbenv;
region = lt->reginfo.primary;
- LOCK_SYSTEM_LOCK(dbenv);
- LOCKER_LOCK(lt, region, locker, indx);
+ if (sh_locker == NULL)
+ return (0);
- if ((ret = __lock_getlocker(lt,
- locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL)
- goto err;
+ LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_LOCKERS(dbenv, region);
if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) {
ret = EINVAL;
@@ -382,9 +425,10 @@ __lock_freefamilylocker(lt, locker)
if (sh_locker->master_locker != INVALID_ROFF)
SH_LIST_REMOVE(sh_locker, child_link, __db_locker);
- __lock_freelocker(lt, region, sh_locker, indx);
+ ret = __lock_freelocker(lt, region, sh_locker);
err: LOCK_SYSTEM_UNLOCK(dbenv);
+ UNLOCK_LOCKERS(dbenv, region);
return (ret);
}
@@ -393,20 +437,22 @@ err: LOCK_SYSTEM_UNLOCK(dbenv);
* Common code for deleting a locker; must be called with the
* locker bucket locked.
*
- * PUBLIC: void __lock_freelocker
- * PUBLIC: __P((DB_LOCKTAB *, DB_LOCKREGION *, DB_LOCKER *, u_int32_t));
+ * PUBLIC: int __lock_freelocker
+ * PUBLIC: __P((DB_LOCKTAB *, DB_LOCKREGION *, DB_LOCKER *));
*/
-void
-__lock_freelocker(lt, region, sh_locker, indx)
+int
+__lock_freelocker(lt, region, sh_locker)
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
DB_LOCKER *sh_locker;
- u_int32_t indx;
{
+ u_int32_t indx;
+ LOCKER_HASH(lt, region, sh_locker->id, indx);
SH_TAILQ_REMOVE(&lt->locker_tab[indx], sh_locker, links, __db_locker);
SH_TAILQ_INSERT_HEAD(
&region->free_lockers, sh_locker, links, __db_locker);
SH_TAILQ_REMOVE(&region->lockers, sh_locker, ulinks, __db_locker);
region->stat.st_nlockers--;
+ return (0);
}
diff --git a/db/lock/lock_list.c b/db/lock/lock_list.c
index ab1db32e0..fac963fef 100644
--- a/db/lock/lock_list.c
+++ b/db/lock/lock_list.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_list.c,v 12.9 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_list.c,v 12.12 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"
@@ -214,13 +213,14 @@ not_ilock: size = nfid * sizeof(DB_LOCK_ILOCK);
}
/*
- * PUBLIC: int __lock_get_list __P((DB_ENV *, u_int32_t, u_int32_t,
+ * PUBLIC: int __lock_get_list __P((DB_ENV *, DB_LOCKER *, u_int32_t,
* PUBLIC: db_lockmode_t, DBT *));
*/
int
__lock_get_list(dbenv, locker, flags, lock_mode, list)
DB_ENV *dbenv;
- u_int32_t locker, flags;
+ DB_LOCKER *locker;
+ u_int32_t flags;
db_lockmode_t lock_mode;
DBT *list;
{
diff --git a/db/lock/lock_method.c b/db/lock/lock_method.c
index 0ca08dc01..b21760aaa 100644
--- a/db/lock/lock_method.c
+++ b/db/lock/lock_method.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_method.c,v 12.13 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_method.c,v 12.17 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"
@@ -13,13 +12,13 @@
#include "dbinc/lock.h"
/*
- * __lock_dbenv_create --
+ * __lock_env_create --
* Lock specific creation of the DB_ENV structure.
*
- * PUBLIC: int __lock_dbenv_create __P((DB_ENV *));
+ * PUBLIC: int __lock_env_create __P((DB_ENV *));
*/
int
-__lock_dbenv_create(dbenv)
+__lock_env_create(dbenv)
DB_ENV *dbenv;
{
/*
@@ -36,13 +35,13 @@ __lock_dbenv_create(dbenv)
}
/*
- * __lock_dbenv_destroy --
+ * __lock_env_destroy --
* Lock specific destruction of the DB_ENV structure.
*
- * PUBLIC: void __lock_dbenv_destroy __P((DB_ENV *));
+ * PUBLIC: void __lock_env_destroy __P((DB_ENV *));
*/
void
-__lock_dbenv_destroy(dbenv)
+__lock_env_destroy(dbenv)
DB_ENV *dbenv;
{
if (dbenv->lk_conflicts != NULL) {
@@ -132,9 +131,9 @@ __lock_get_lk_detect(dbenv, lk_detectp)
if (LOCKING_ON(dbenv)) {
lt = dbenv->lk_handle;
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_REGION_LOCK(dbenv);
*lk_detectp = ((DB_LOCKREGION *)lt->reginfo.primary)->detect;
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
} else
*lk_detectp = dbenv->lk_detect;
return (0);
@@ -179,7 +178,7 @@ __lock_set_lk_detect(dbenv, lk_detect)
if (LOCKING_ON(dbenv)) {
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_REGION_LOCK(dbenv);
/*
* Check for incompatible automatic deadlock detection requests.
* There are scenarios where changing the detector configuration
@@ -198,7 +197,7 @@ __lock_set_lk_detect(dbenv, lk_detect)
} else
if (region->detect == DB_LOCK_NORUN)
region->detect = lk_detect;
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
} else
dbenv->lk_detect = lk_detect;
@@ -337,7 +336,7 @@ __lock_get_env_timeout(dbenv, timeoutp, flag)
if (LOCKING_ON(dbenv)) {
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_REGION_LOCK(dbenv);
switch (flag) {
case DB_SET_LOCK_TIMEOUT:
*timeoutp = region->lk_timeout;
@@ -349,7 +348,7 @@ __lock_get_env_timeout(dbenv, timeoutp, flag)
ret = 1;
break;
}
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
} else
switch (flag) {
case DB_SET_LOCK_TIMEOUT:
@@ -392,7 +391,7 @@ __lock_set_env_timeout(dbenv, timeout, flags)
if (LOCKING_ON(dbenv)) {
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_REGION_LOCK(dbenv);
switch (flags) {
case DB_SET_LOCK_TIMEOUT:
region->lk_timeout = timeout;
@@ -404,7 +403,7 @@ __lock_set_env_timeout(dbenv, timeout, flags)
ret = 1;
break;
}
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
} else
switch (flags) {
case DB_SET_LOCK_TIMEOUT:
diff --git a/db/lock/lock_region.c b/db/lock/lock_region.c
index c3a1b401d..ece4e2e6f 100644
--- a/db/lock/lock_region.c
+++ b/db/lock/lock_region.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_region.c,v 12.11 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_region.c,v 12.18 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"
@@ -53,11 +52,12 @@ static const u_int8_t db_cdb_conflicts[] = {
* __lock_open --
* Internal version of lock_open: only called from DB_ENV->open.
*
- * PUBLIC: int __lock_open __P((DB_ENV *));
+ * PUBLIC: int __lock_open __P((DB_ENV *, int));
*/
int
-__lock_open(dbenv)
+__lock_open(dbenv, create_ok)
DB_ENV *dbenv;
+ int create_ok;
{
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
@@ -76,10 +76,10 @@ __lock_open(dbenv)
lt->reginfo.type = REGION_TYPE_LOCK;
lt->reginfo.id = INVALID_REGION_ID;
lt->reginfo.flags = REGION_JOIN_OK;
- if (F_ISSET(dbenv, DB_ENV_CREATE))
+ if (create_ok)
F_SET(&lt->reginfo, REGION_CREATE_OK);
size = __lock_region_size(dbenv);
- if ((ret = __db_r_attach(dbenv, &lt->reginfo, size)) != 0)
+ if ((ret = __env_region_attach(dbenv, &lt->reginfo, size)) != 0)
goto err;
/* If we created the region, initialize it. */
@@ -94,6 +94,10 @@ __lock_open(dbenv)
/* Set remaining pointers into region. */
lt->conflicts = R_ADDR(&lt->reginfo, region->conf_off);
lt->obj_tab = R_ADDR(&lt->reginfo, region->obj_off);
+ lt->obj_stat = R_ADDR(&lt->reginfo, region->stat_off);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ lt->obj_mtx = R_ADDR(&lt->reginfo, region->mtx_off);
+#endif
lt->locker_tab = R_ADDR(&lt->reginfo, region->locker_off);
dbenv->lk_handle = lt;
@@ -139,9 +143,10 @@ __lock_open(dbenv)
err: dbenv->lk_handle = NULL;
if (lt->reginfo.addr != NULL) {
- if (region_locked)
+ if (region_locked) {
LOCK_SYSTEM_UNLOCK(dbenv);
- (void)__db_r_detach(dbenv, &lt->reginfo, 0);
+ }
+ (void)__env_region_detach(dbenv, &lt->reginfo, 0);
}
__os_free(dbenv, lt);
@@ -162,12 +167,15 @@ __lock_region_init(dbenv, lt)
DB_LOCKER *lidp;
DB_LOCKOBJ *op;
DB_LOCKREGION *region;
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ db_mutex_t *mtxp;
+#endif
u_int32_t i;
u_int8_t *addr;
int lk_modes, ret;
- if ((ret = __db_shalloc(&lt->reginfo,
- sizeof(DB_LOCKREGION), 0, &lt->reginfo.primary)) != 0)
+ if ((ret = __env_alloc(&lt->reginfo,
+ sizeof(DB_LOCKREGION), &lt->reginfo.primary)) != 0)
goto mem_err;
lt->reginfo.rp->primary = R_OFFSET(&lt->reginfo, lt->reginfo.primary);
region = lt->reginfo.primary;
@@ -192,7 +200,7 @@ __lock_region_init(dbenv, lt)
}
region->need_dd = 0;
- LOCK_SET_TIME_INVALID(&region->next_timeout);
+ timespecclear(&region->next_timeout);
region->detect = DB_LOCK_NORUN;
region->lk_timeout = dbenv->lk_timeout;
region->tx_timeout = dbenv->tx_timeout;
@@ -207,22 +215,51 @@ __lock_region_init(dbenv, lt)
region->stat.st_nmodes = lk_modes;
/* Allocate room for the conflict matrix and initialize it. */
- if ((ret = __db_shalloc(
- &lt->reginfo, (size_t)(lk_modes * lk_modes), 0, &addr)) != 0)
+ if ((ret = __env_alloc(
+ &lt->reginfo, (size_t)(lk_modes * lk_modes), &addr)) != 0)
goto mem_err;
memcpy(addr, lk_conflicts, (size_t)(lk_modes * lk_modes));
region->conf_off = R_OFFSET(&lt->reginfo, addr);
/* Allocate room for the object hash table and initialize it. */
- if ((ret = __db_shalloc(&lt->reginfo,
- region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
+ if ((ret = __env_alloc(&lt->reginfo,
+ region->object_t_size * sizeof(DB_HASHTAB), &addr)) != 0)
goto mem_err;
__db_hashinit(addr, region->object_t_size);
region->obj_off = R_OFFSET(&lt->reginfo, addr);
+ /* Allocate room for the object hash stats table and initialize it. */
+ if ((ret = __env_alloc(&lt->reginfo,
+ region->object_t_size * sizeof(DB_LOCK_HSTAT), &addr)) != 0)
+ goto mem_err;
+ memset(addr, 0, region->object_t_size * sizeof(DB_LOCK_HSTAT));
+ region->stat_off = R_OFFSET(&lt->reginfo, addr);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ if ((ret = __env_alloc(&lt->reginfo,
+ region->object_t_size * sizeof(db_mutex_t), &mtxp)) != 0)
+ goto mem_err;
+ region->mtx_off = R_OFFSET(&lt->reginfo, mtxp);
+ for (i = 0; i < region->object_t_size; i++) {
+ if ((ret = __mutex_alloc(
+ dbenv, MTX_LOCK_REGION, 0, &mtxp[i])) != 0)
+ return (ret);
+ }
+ if ((ret = __mutex_alloc(
+ dbenv, MTX_LOCK_REGION, 0, &region->mtx_objs)) != 0)
+ return (ret);
+
+ if ((ret = __mutex_alloc(
+ dbenv, MTX_LOCK_REGION, 0, &region->mtx_locks)) != 0)
+ return (ret);
+
+ if ((ret = __mutex_alloc(
+ dbenv, MTX_LOCK_REGION, 0, &region->mtx_lockers)) != 0)
+ return (ret);
+
+#endif
/* Allocate room for the locker hash table and initialize it. */
- if ((ret = __db_shalloc(&lt->reginfo,
- region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
+ if ((ret = __env_alloc(&lt->reginfo,
+ region->locker_t_size * sizeof(DB_HASHTAB), &addr)) != 0)
goto mem_err;
__db_hashinit(addr, region->locker_t_size);
region->locker_off = R_OFFSET(&lt->reginfo, addr);
@@ -230,8 +267,8 @@ __lock_region_init(dbenv, lt)
/* Initialize locks onto a free list. */
SH_TAILQ_INIT(&region->free_locks);
for (i = 0; i < region->stat.st_maxlocks; ++i) {
- if ((ret = __db_shalloc(&lt->reginfo,
- sizeof(struct __db_lock), 0, &lp)) != 0)
+ if ((ret = __env_alloc(&lt->reginfo,
+ sizeof(struct __db_lock), &lp)) != 0)
goto mem_err;
lp->mtx_lock = MUTEX_INVALID;
lp->gen = 0;
@@ -243,21 +280,22 @@ __lock_region_init(dbenv, lt)
SH_TAILQ_INIT(&region->dd_objs);
SH_TAILQ_INIT(&region->free_objs);
for (i = 0; i < region->stat.st_maxobjects; ++i) {
- if ((ret = __db_shalloc(&lt->reginfo,
- sizeof(DB_LOCKOBJ), 0, &op)) != 0)
+ if ((ret = __env_alloc(&lt->reginfo,
+ sizeof(DB_LOCKOBJ), &op)) != 0)
goto mem_err;
SH_TAILQ_INSERT_HEAD(
&region->free_objs, op, links, __db_lockobj);
+ op->generation = 0;
}
/* Initialize lockers onto a free list. */
SH_TAILQ_INIT(&region->lockers);
SH_TAILQ_INIT(&region->free_lockers);
for (i = 0; i < region->stat.st_maxlockers; ++i) {
- if ((ret = __db_shalloc(&lt->reginfo,
- sizeof(DB_LOCKER), 0, &lidp)) != 0) {
+ if ((ret =
+ __env_alloc(&lt->reginfo, sizeof(DB_LOCKER), &lidp)) != 0) {
mem_err: __db_errx(dbenv,
- "Unable to allocate memory for the lock table");
+ "unable to allocate memory for the lock table");
return (ret);
}
SH_TAILQ_INSERT_HEAD(
@@ -268,13 +306,13 @@ mem_err: __db_errx(dbenv,
}
/*
- * __lock_dbenv_refresh --
+ * __lock_env_refresh --
* Clean up after the lock system on a close or failed open.
*
- * PUBLIC: int __lock_dbenv_refresh __P((DB_ENV *));
+ * PUBLIC: int __lock_env_refresh __P((DB_ENV *));
*/
int
-__lock_dbenv_refresh(dbenv)
+__lock_env_refresh(dbenv)
DB_ENV *dbenv;
{
struct __db_lock *lp;
@@ -296,19 +334,19 @@ __lock_dbenv_refresh(dbenv)
*/
if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
/* Discard the conflict matrix. */
- __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->conf_off));
+ __env_alloc_free(reginfo, R_ADDR(reginfo, lr->conf_off));
/* Discard the object hash table. */
- __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->obj_off));
+ __env_alloc_free(reginfo, R_ADDR(reginfo, lr->obj_off));
/* Discard the locker hash table. */
- __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->locker_off));
+ __env_alloc_free(reginfo, R_ADDR(reginfo, lr->locker_off));
/* Discard locks. */
while ((lp =
SH_TAILQ_FIRST(&lr->free_locks, __db_lock)) != NULL) {
SH_TAILQ_REMOVE(&lr->free_locks, lp, links, __db_lock);
- __db_shalloc_free(reginfo, lp);
+ __env_alloc_free(reginfo, lp);
}
/* Discard objects. */
@@ -316,7 +354,7 @@ __lock_dbenv_refresh(dbenv)
SH_TAILQ_FIRST(&lr->free_objs, __db_lockobj)) != NULL) {
SH_TAILQ_REMOVE(
&lr->free_objs, lockobj, links, __db_lockobj);
- __db_shalloc_free(reginfo, lockobj);
+ __env_alloc_free(reginfo, lockobj);
}
/* Discard lockers. */
@@ -324,12 +362,12 @@ __lock_dbenv_refresh(dbenv)
SH_TAILQ_FIRST(&lr->free_lockers, __db_locker)) != NULL) {
SH_TAILQ_REMOVE(
&lr->free_lockers, locker, links, __db_locker);
- __db_shalloc_free(reginfo, locker);
+ __env_alloc_free(reginfo, locker);
}
}
/* Detach from the region. */
- ret = __db_r_detach(dbenv, reginfo, 0);
+ ret = __env_region_detach(dbenv, reginfo, 0);
/* Discard DB_LOCKTAB. */
__os_free(dbenv, lt);
@@ -348,7 +386,11 @@ u_int32_t
__lock_region_mutex_count(dbenv)
DB_ENV *dbenv;
{
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ return (dbenv->lk_max + __db_tablesize(dbenv->lk_max_objects) + 3);
+#else
return (dbenv->lk_max);
+#endif
}
/*
@@ -363,28 +405,26 @@ __lock_region_size(dbenv)
/*
* Figure out how much space we're going to need. This list should
- * map one-to-one with the __db_shalloc calls in __lock_region_init.
+ * map one-to-one with the __env_alloc calls in __lock_region_init.
*/
retval = 0;
- retval += __db_shalloc_size(sizeof(DB_LOCKREGION), 0);
- retval += __db_shalloc_size(
- (size_t)(dbenv->lk_modes * dbenv->lk_modes), 0);
- retval += __db_shalloc_size(
- __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)), 0);
- retval += __db_shalloc_size(
- __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)), 0);
- retval +=
- __db_shalloc_size(sizeof(struct __db_lock), 0) * dbenv->lk_max;
- retval +=
- __db_shalloc_size(sizeof(DB_LOCKOBJ), 0) * dbenv->lk_max_objects;
- retval +=
- __db_shalloc_size(sizeof(DB_LOCKER), 0) * dbenv->lk_max_lockers;
+ retval += __env_alloc_size(sizeof(DB_LOCKREGION));
+ retval += __env_alloc_size((size_t)(dbenv->lk_modes * dbenv->lk_modes));
+ retval += __env_alloc_size(
+ __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)));
+ retval += __env_alloc_size(
+ __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_LOCK_HSTAT)));
+ retval += __env_alloc_size(
+ __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)));
+ retval += __env_alloc_size(sizeof(struct __db_lock)) * dbenv->lk_max;
+ retval += __env_alloc_size(sizeof(DB_LOCKOBJ)) * dbenv->lk_max_objects;
+ retval += __env_alloc_size(sizeof(DB_LOCKER)) * dbenv->lk_max_lockers;
/*
* Include 16 bytes of string space per lock. DB doesn't use it
* because we pre-allocate lock space for DBTs in the structure.
*/
- retval += __db_shalloc_size(dbenv->lk_max * 16, sizeof(size_t));
+ retval += __env_alloc_size(dbenv->lk_max * 16);
/* And we keep getting this wrong, let's be generous. */
retval += retval / 4;
diff --git a/db/lock/lock_stat.c b/db/lock/lock_stat.c
index 90bb57bb7..7fedcd830 100644
--- a/db/lock/lock_stat.c
+++ b/db/lock/lock_stat.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_stat.c,v 12.17 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_stat.c,v 12.29 2007/06/22 17:38:24 bostic Exp $
*/
#include "db_config.h"
@@ -67,6 +66,7 @@ __lock_stat(dbenv, statp, flags)
DB_LOCKTAB *lt;
DB_LOCK_STAT *stats, tmp;
int ret;
+ u_int32_t i;
*statp = NULL;
lt = dbenv->lk_handle;
@@ -75,20 +75,58 @@ __lock_stat(dbenv, statp, flags)
return (ret);
/* Copy out the global statistics. */
- LOCK_SYSTEM_LOCK(dbenv);
+ LOCK_REGION_LOCK(dbenv);
region = lt->reginfo.primary;
memcpy(stats, &region->stat, sizeof(*stats));
stats->st_locktimeout = region->lk_timeout;
stats->st_txntimeout = region->tx_timeout;
+ for (i = 0; i < region->object_t_size; i++) {
+ stats->st_nrequests += lt->obj_stat[i].st_nrequests;
+ stats->st_nreleases += lt->obj_stat[i].st_nreleases;
+ stats->st_nupgrade += lt->obj_stat[i].st_nupgrade;
+ stats->st_ndowngrade += lt->obj_stat[i].st_ndowngrade;
+ stats->st_lock_wait += lt->obj_stat[i].st_lock_wait;
+ stats->st_lock_nowait += lt->obj_stat[i].st_lock_nowait;
+ stats->st_nlocktimeouts += lt->obj_stat[i].st_nlocktimeouts;
+ stats->st_ntxntimeouts += lt->obj_stat[i].st_ntxntimeouts;
+ if (stats->st_hash_len < lt->obj_stat[i].st_hash_len)
+ stats->st_hash_len = lt->obj_stat[i].st_hash_len;
+ if (LF_ISSET(DB_STAT_CLEAR)) {
+ memset(&lt->obj_stat[i], 0, sizeof(lt->obj_stat[i]));
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ if (!LF_ISSET(DB_STAT_SUBSYSTEM))
+ __mutex_clear(dbenv, lt->obj_mtx[i]);
+#endif
+ }
+ }
+
__mutex_set_wait_info(dbenv, region->mtx_region,
&stats->st_region_wait, &stats->st_region_nowait);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ __mutex_set_wait_info(dbenv, region->mtx_objs,
+ &stats->st_objs_wait, &stats->st_objs_nowait);
+ __mutex_set_wait_info(dbenv, region->mtx_lockers,
+ &stats->st_lockers_wait, &stats->st_lockers_nowait);
+ __mutex_set_wait_info(dbenv, region->mtx_locks,
+ &stats->st_locks_wait, &stats->st_locks_nowait);
+#endif
stats->st_regsize = lt->reginfo.rp->size;
if (LF_ISSET(DB_STAT_CLEAR)) {
tmp = region->stat;
memset(&region->stat, 0, sizeof(region->stat));
- __mutex_clear(dbenv, region->mtx_region);
+ if (!LF_ISSET(DB_STAT_SUBSYSTEM)) {
+ __mutex_clear(dbenv, region->mtx_region);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ __mutex_clear(dbenv, region->mtx_objs);
+ __mutex_clear(dbenv, region->mtx_locks);
+ __mutex_clear(dbenv, region->mtx_lockers);
+#endif
+ for (i = 0; i < region->object_t_size; i++)
+ memset(&lt->obj_stat[i],
+ 0, sizeof(lt->obj_stat[i]));
+ }
region->stat.st_id = tmp.st_id;
region->stat.st_cur_maxid = tmp.st_cur_maxid;
@@ -104,7 +142,7 @@ __lock_stat(dbenv, statp, flags)
region->stat.st_nmodes = tmp.st_nmodes;
}
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
*statp = stats;
return (0);
@@ -156,7 +194,7 @@ __lock_stat_print(dbenv, flags)
int ret;
orig_flags = flags;
- LF_CLR(DB_STAT_CLEAR);
+ LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
ret = __lock_print_stats(dbenv, orig_flags);
if (flags == 0 || ret != 0)
@@ -183,6 +221,55 @@ __lock_print_stats(dbenv, flags)
DB_LOCK_STAT *sp;
int ret;
+#ifdef LOCK_DIAGNOSTIC
+ DB_LOCKTAB *lt;
+ DB_LOCKREGION *region;
+ u_int32_t i;
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ u_int32_t wait, nowait;
+#endif
+
+ lt = dbenv->lk_handle;
+ region = lt->reginfo.primary;
+
+ for (i = 0; i < region->object_t_size; i++) {
+ if (lt->obj_stat[i].st_hash_len == 0)
+ continue;
+ __db_dl(dbenv,
+ "Hash bucket", (u_long)i);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ __mutex_set_wait_info(dbenv, lt->obj_mtx[i], &wait, &nowait);
+ __db_dl_pct(dbenv,
+ "The number of hash mutex requests that required waiting",
+ (u_long)wait, DB_PCT(wait, wait + nowait), NULL);
+#endif
+ __db_dl(dbenv,
+ "Maximum hash bucket length",
+ (u_long)lt->obj_stat[i].st_hash_len);
+ __db_dl(dbenv,
+ "Total number of locks requested",
+ (u_long)lt->obj_stat[i].st_nrequests);
+ __db_dl(dbenv,
+ "Total number of locks released",
+ (u_long)lt->obj_stat[i].st_nreleases);
+ __db_dl(dbenv,
+ "Total number of locks upgraded",
+ (u_long)lt->obj_stat[i].st_nupgrade);
+ __db_dl(dbenv,
+ "Total number of locks downgraded",
+ (u_long)lt->obj_stat[i].st_ndowngrade);
+ __db_dl(dbenv,
+ "Lock requests not available due to conflicts, for which we waited",
+ (u_long)lt->obj_stat[i].st_lock_wait);
+ __db_dl(dbenv,
+ "Lock requests not available due to conflicts, for which we did not wait",
+ (u_long)lt->obj_stat[i].st_lock_nowait);
+ __db_dl(dbenv, "Number of locks that have timed out",
+ (u_long)lt->obj_stat[i].st_nlocktimeouts);
+ __db_dl(dbenv, "Number of transactions that have timed out",
+ (u_long)lt->obj_stat[i].st_ntxntimeouts);
+ }
+#endif
if ((ret = __lock_stat(dbenv, &sp, flags)) != 0)
return (ret);
@@ -233,6 +320,20 @@ __lock_print_stats(dbenv, flags)
__db_dlbytes(dbenv, "The size of the lock region",
(u_long)0, (u_long)0, (u_long)sp->st_regsize);
+#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER
+ __db_dl_pct(dbenv,
+ "The number of object allocations that required waiting",
+ (u_long)sp->st_objs_wait, DB_PCT(sp->st_objs_wait,
+ sp->st_objs_wait + sp->st_objs_nowait), NULL);
+ __db_dl_pct(dbenv,
+ "The number of locker allocations that required waiting",
+ (u_long)sp->st_lockers_wait, DB_PCT(sp->st_lockers_wait,
+ sp->st_lockers_wait + sp->st_lockers_nowait), NULL);
+ __db_dl_pct(dbenv,
+ "The number of lock allocations that required waiting",
+ (u_long)sp->st_locks_wait, DB_PCT(sp->st_locks_wait,
+ sp->st_locks_wait + sp->st_locks_nowait), NULL);
+#endif
__db_dl_pct(dbenv,
"The number of region locks that required waiting",
(u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait,
@@ -264,9 +365,8 @@ __lock_print_all(dbenv, flags)
lrp = lt->reginfo.primary;
DB_MSGBUF_INIT(&mb);
- LOCK_SYSTEM_LOCK(dbenv);
-
- __db_print_reginfo(dbenv, &lt->reginfo, "Lock");
+ LOCK_REGION_LOCK(dbenv);
+ __db_print_reginfo(dbenv, &lt->reginfo, "Lock", flags);
if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_PARAMS)) {
__db_msg(dbenv, "%s", DB_GLOBAL(db_line));
@@ -278,18 +378,19 @@ __lock_print_all(dbenv, flags)
STAT_ULONG("obj_off", lrp->obj_off);
STAT_ULONG("locker_off", lrp->locker_off);
STAT_ULONG("need_dd", lrp->need_dd);
- if (LOCK_TIME_ISVALID(&lrp->next_timeout)) {
+ if (timespecisset(&lrp->next_timeout)) {
#ifdef HAVE_STRFTIME
time_t t = (time_t)lrp->next_timeout.tv_sec;
char tbuf[64];
if (strftime(tbuf, sizeof(tbuf),
"%m-%d-%H:%M:%S", localtime(&t)) != 0)
- __db_msg(dbenv, "next_timeout: %s.%lu",
- tbuf, (u_long)lrp->next_timeout.tv_usec);
+ __db_msg(dbenv, "next_timeout: %s.%09lu",
+ tbuf, (u_long)lrp->next_timeout.tv_nsec);
else
#endif
- __db_msg(dbenv, "next_timeout: %lu",
- (u_long)lrp->next_timeout.tv_usec);
+ __db_msg(dbenv, "next_timeout: %lu.%09lu",
+ (u_long)lrp->next_timeout.tv_sec,
+ (u_long)lrp->next_timeout.tv_nsec);
}
}
@@ -303,6 +404,7 @@ __lock_print_all(dbenv, flags)
DB_MSGBUF_FLUSH(dbenv, &mb);
}
}
+ LOCK_REGION_UNLOCK(dbenv);
if (LF_ISSET(DB_STAT_ALL | DB_STAT_LOCK_LOCKERS)) {
__db_msg(dbenv, "%s", DB_GLOBAL(db_line));
@@ -325,7 +427,6 @@ __lock_print_all(dbenv, flags)
__db_msg(dbenv, "%s", "");
}
}
- LOCK_SYSTEM_UNLOCK(dbenv);
return (0);
}
@@ -346,33 +447,35 @@ __lock_dump_locker(dbenv, mbp, lt, lip)
dbenv->thread_id_string(dbenv, lip->pid, lip->tid, buf));
__db_msgadd(
dbenv, mbp, "%s", F_ISSET(lip, DB_LOCKER_DELETED) ? "(D)" : " ");
- if (LOCK_TIME_ISVALID(&lip->tx_expire)) {
+ if (timespecisset(&lip->tx_expire)) {
#ifdef HAVE_STRFTIME
time_t t = (time_t)lip->tx_expire.tv_sec;
char tbuf[64];
if (strftime(tbuf, sizeof(tbuf),
"%m-%d-%H:%M:%S", localtime(&t)) != 0)
- __db_msgadd(dbenv, mbp, "expires %s.%lu",
- tbuf, (u_long)lip->tx_expire.tv_usec);
+ __db_msgadd(dbenv, mbp, "expires %s.%09lu",
+ tbuf, (u_long)lip->tx_expire.tv_nsec);
else
#endif
- __db_msgadd(dbenv, mbp, "expires %lu",
- (u_long)lip->tx_expire.tv_usec);
+ __db_msgadd(dbenv, mbp, "expires %lu.%09lu",
+ (u_long)lip->tx_expire.tv_sec,
+ (u_long)lip->tx_expire.tv_nsec);
}
if (F_ISSET(lip, DB_LOCKER_TIMEOUT))
__db_msgadd(dbenv, mbp, " lk timeout %u", lip->lk_timeout);
- if (LOCK_TIME_ISVALID(&lip->lk_expire)) {
+ if (timespecisset(&lip->lk_expire)) {
#ifdef HAVE_STRFTIME
time_t t = (time_t)lip->lk_expire.tv_sec;
char tbuf[64];
if (strftime(tbuf,
sizeof(tbuf), "%m-%d-%H:%M:%S", localtime(&t)) != 0)
- __db_msgadd(dbenv, mbp, " lk expires %s.%lu",
- tbuf, (u_long)lip->lk_expire.tv_usec);
+ __db_msgadd(dbenv, mbp, " lk expires %s.%09lu",
+ tbuf, (u_long)lip->lk_expire.tv_nsec);
else
#endif
- __db_msgadd(dbenv, mbp, " lk expires %lu",
- (u_long)lip->lk_expire.tv_usec);
+ __db_msgadd(dbenv, mbp, " lk expires %lu.%09lu",
+ (u_long)lip->lk_expire.tv_sec,
+ (u_long)lip->lk_expire.tv_nsec);
}
DB_MSGBUF_FLUSH(dbenv, mbp);
@@ -491,7 +594,8 @@ __lock_printlock(lt, mbp, lp, ispgno)
break;
}
__db_msgadd(dbenv, mbp, "%8lx %-10s %4lu %-7s ",
- (u_long)lp->holder, mode, (u_long)lp->refcount, status);
+ (u_long)((DB_LOCKER *)R_ADDR(&lt->reginfo, lp->holder))->id,
+ mode, (u_long)lp->refcount, status);
lockobj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
ptr = SH_DBT_PTR(&lockobj->lockobj);
diff --git a/db/lock/lock_stub.c b/db/lock/lock_stub.c
new file mode 100644
index 000000000..8c210f67e
--- /dev/null
+++ b/db/lock/lock_stub.c
@@ -0,0 +1,491 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
+ *
+ * $Id: lock_stub.c,v 12.7 2007/05/17 15:15:43 bostic Exp $
+ */
+
+#include "db_config.h"
+
+#include "db_int.h"
+#include "dbinc/lock.h"
+
+/*
+ * If the library wasn't compiled with locking support, various routines
+ * aren't available. Stub them here, returning an appropriate error.
+ */
+static int __db_nolocking __P((DB_ENV *));
+
+/*
+ * __db_nolocking --
+ * Error when a Berkeley DB build doesn't include the locking subsystem.
+ */
+static int
+__db_nolocking(dbenv)
+ DB_ENV *dbenv;
+{
+ __db_errx(dbenv,
+ "library build did not include support for locking");
+ return (DB_OPNOTSUP);
+}
+
+int
+__lock_env_create(dbenv)
+ DB_ENV *dbenv;
+{
+ COMPQUIET(dbenv, 0);
+ return (0);
+}
+
+void
+__lock_env_destroy(dbenv)
+ DB_ENV *dbenv;
+{
+ COMPQUIET(dbenv, 0);
+}
+
+int
+__lock_get_lk_conflicts(dbenv, lk_conflictsp, lk_modesp)
+ DB_ENV *dbenv;
+ const u_int8_t **lk_conflictsp;
+ int *lk_modesp;
+{
+ COMPQUIET(lk_conflictsp, NULL);
+ COMPQUIET(lk_modesp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_lk_detect(dbenv, lk_detectp)
+ DB_ENV *dbenv;
+ u_int32_t *lk_detectp;
+{
+ COMPQUIET(lk_detectp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_lk_max_lockers(dbenv, lk_maxp)
+ DB_ENV *dbenv;
+ u_int32_t *lk_maxp;
+{
+ COMPQUIET(lk_maxp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_lk_max_locks(dbenv, lk_maxp)
+ DB_ENV *dbenv;
+ u_int32_t *lk_maxp;
+{
+ COMPQUIET(lk_maxp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_lk_max_objects(dbenv, lk_maxp)
+ DB_ENV *dbenv;
+ u_int32_t *lk_maxp;
+{
+ COMPQUIET(lk_maxp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_env_timeout(dbenv, timeoutp, flag)
+ DB_ENV *dbenv;
+ db_timeout_t *timeoutp;
+ u_int32_t flag;
+{
+ COMPQUIET(timeoutp, NULL);
+ COMPQUIET(flag, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_detect_pp(dbenv, flags, atype, abortp)
+ DB_ENV *dbenv;
+ u_int32_t flags, atype;
+ int *abortp;
+{
+ COMPQUIET(flags, 0);
+ COMPQUIET(atype, 0);
+ COMPQUIET(abortp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_get_pp(dbenv, locker, flags, obj, lock_mode, lock)
+ DB_ENV *dbenv;
+ u_int32_t locker, flags;
+ const DBT *obj;
+ db_lockmode_t lock_mode;
+ DB_LOCK *lock;
+{
+ COMPQUIET(locker, 0);
+ COMPQUIET(flags, 0);
+ COMPQUIET(obj, NULL);
+ COMPQUIET(lock_mode, 0);
+ COMPQUIET(lock, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_id_pp(dbenv, idp)
+ DB_ENV *dbenv;
+ u_int32_t *idp;
+{
+ COMPQUIET(idp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_id_free_pp(dbenv, id)
+ DB_ENV *dbenv;
+ u_int32_t id;
+{
+ COMPQUIET(id, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_put_pp(dbenv, lock)
+ DB_ENV *dbenv;
+ DB_LOCK *lock;
+{
+ COMPQUIET(lock, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_stat_pp(dbenv, statp, flags)
+ DB_ENV *dbenv;
+ DB_LOCK_STAT **statp;
+ u_int32_t flags;
+{
+ COMPQUIET(statp, NULL);
+ COMPQUIET(flags, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_stat_print_pp(dbenv, flags)
+ DB_ENV *dbenv;
+ u_int32_t flags;
+{
+ COMPQUIET(flags, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_vec_pp(dbenv, locker, flags, list, nlist, elistp)
+ DB_ENV *dbenv;
+ u_int32_t locker, flags;
+ int nlist;
+ DB_LOCKREQ *list, **elistp;
+{
+ COMPQUIET(locker, 0);
+ COMPQUIET(flags, 0);
+ COMPQUIET(list, NULL);
+ COMPQUIET(nlist, 0);
+ COMPQUIET(elistp, NULL);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_lk_conflicts(dbenv, lk_conflicts, lk_modes)
+ DB_ENV *dbenv;
+ u_int8_t *lk_conflicts;
+ int lk_modes;
+{
+ COMPQUIET(lk_conflicts, NULL);
+ COMPQUIET(lk_modes, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_lk_detect(dbenv, lk_detect)
+ DB_ENV *dbenv;
+ u_int32_t lk_detect;
+{
+ COMPQUIET(lk_detect, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_lk_max_locks(dbenv, lk_max)
+ DB_ENV *dbenv;
+ u_int32_t lk_max;
+{
+ COMPQUIET(lk_max, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_lk_max_lockers(dbenv, lk_max)
+ DB_ENV *dbenv;
+ u_int32_t lk_max;
+{
+ COMPQUIET(lk_max, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_lk_max_objects(dbenv, lk_max)
+ DB_ENV *dbenv;
+ u_int32_t lk_max;
+{
+ COMPQUIET(lk_max, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_set_env_timeout(dbenv, timeout, flags)
+ DB_ENV *dbenv;
+ db_timeout_t timeout;
+ u_int32_t flags;
+{
+ COMPQUIET(timeout, 0);
+ COMPQUIET(flags, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_open(dbenv, create_ok)
+ DB_ENV *dbenv;
+ int create_ok;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(create_ok, 0);
+ return (__db_nolocking(dbenv));
+}
+
+int
+__lock_id_free(dbenv, sh_locker)
+ DB_ENV *dbenv;
+ DB_LOCKER *sh_locker;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(sh_locker, 0);
+ return (0);
+}
+
+int
+__lock_env_refresh(dbenv)
+ DB_ENV *dbenv;
+{
+ COMPQUIET(dbenv, NULL);
+ return (0);
+}
+
+int
+__lock_stat_print(dbenv, flags)
+ DB_ENV *dbenv;
+ u_int32_t flags;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(flags, 0);
+ return (0);
+}
+
+int
+__lock_put(dbenv, lock)
+ DB_ENV *dbenv;
+ DB_LOCK *lock;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(lock, NULL);
+ return (0);
+}
+
+int
+__lock_vec(dbenv, sh_locker, flags, list, nlist, elistp)
+ DB_ENV *dbenv;
+ DB_LOCKER *sh_locker;
+ u_int32_t flags;
+ int nlist;
+ DB_LOCKREQ *list, **elistp;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(sh_locker, 0);
+ COMPQUIET(flags, 0);
+ COMPQUIET(list, NULL);
+ COMPQUIET(nlist, 0);
+ COMPQUIET(elistp, NULL);
+ return (0);
+}
+
+int
+__lock_get(dbenv, locker, flags, obj, lock_mode, lock)
+ DB_ENV *dbenv;
+ DB_LOCKER *locker;
+ u_int32_t flags;
+ const DBT *obj;
+ db_lockmode_t lock_mode;
+ DB_LOCK *lock;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(locker, NULL);
+ COMPQUIET(flags, 0);
+ COMPQUIET(obj, NULL);
+ COMPQUIET(lock_mode, 0);
+ COMPQUIET(lock, NULL);
+ return (0);
+}
+
+int
+__lock_id(dbenv, idp, lkp)
+ DB_ENV *dbenv;
+ u_int32_t *idp;
+ DB_LOCKER **lkp;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(idp, NULL);
+ COMPQUIET(lkp, NULL);
+ return (0);
+}
+
+int
+__lock_inherit_timeout(dbenv, parent, locker)
+ DB_ENV *dbenv;
+ DB_LOCKER *parent, *locker;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(parent, NULL);
+ COMPQUIET(locker, NULL);
+ return (0);
+}
+
+int
+__lock_set_timeout(dbenv, locker, timeout, op)
+ DB_ENV *dbenv;
+ DB_LOCKER *locker;
+ db_timeout_t timeout;
+ u_int32_t op;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(locker, NULL);
+ COMPQUIET(timeout, 0);
+ COMPQUIET(op, 0);
+ return (0);
+}
+
+int
+__lock_addfamilylocker(dbenv, pid, id)
+ DB_ENV *dbenv;
+ u_int32_t pid, id;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(pid, 0);
+ COMPQUIET(id, 0);
+ return (0);
+}
+
+int
+__lock_freefamilylocker(lt, sh_locker)
+ DB_LOCKTAB *lt;
+ DB_LOCKER *sh_locker;
+{
+ COMPQUIET(lt, NULL);
+ COMPQUIET(sh_locker, NULL);
+ return (0);
+}
+
+int
+__lock_downgrade(dbenv, lock, new_mode, flags)
+ DB_ENV *dbenv;
+ DB_LOCK *lock;
+ db_lockmode_t new_mode;
+ u_int32_t flags;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(lock, NULL);
+ COMPQUIET(new_mode, 0);
+ COMPQUIET(flags, 0);
+ return (0);
+}
+
+int
+__lock_locker_is_parent(dbenv, locker, child, retp)
+ DB_ENV *dbenv;
+ DB_LOCKER *locker;
+ DB_LOCKER *child;
+ int *retp;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(locker, NULL);
+ COMPQUIET(child, NULL);
+
+ *retp = 1;
+ return (0);
+}
+
+void
+__lock_set_thread_id(lref, pid, tid)
+ void *lref;
+ pid_t pid;
+ db_threadid_t tid;
+{
+ COMPQUIET(lref, NULL);
+ COMPQUIET(pid, 0);
+ COMPQUIET(tid, 0);
+}
+
+int
+__lock_failchk(dbenv)
+ DB_ENV *dbenv;
+{
+ COMPQUIET(dbenv, NULL);
+ return (0);
+}
+
+int
+__lock_get_list(dbenv, locker, flags, lock_mode, list)
+ DB_ENV *dbenv;
+ DB_LOCKER *locker;
+ u_int32_t flags;
+ db_lockmode_t lock_mode;
+ DBT *list;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(locker, NULL);
+ COMPQUIET(flags, 0);
+ COMPQUIET(lock_mode, 0);
+ COMPQUIET(list, NULL);
+ return (0);
+}
+
+void
+__lock_list_print(dbenv, list)
+ DB_ENV *dbenv;
+ DBT *list;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(list, NULL);
+}
+
+int
+__lock_getlocker(lt, locker, create, retp)
+ DB_LOCKTAB *lt;
+ u_int32_t locker;
+ int create;
+ DB_LOCKER **retp;
+{
+ COMPQUIET(lt, NULL);
+ COMPQUIET(locker, 0);
+ COMPQUIET(create, 0);
+ COMPQUIET(retp, NULL);
+ return (__db_nolocking(lt->dbenv));
+}
+
+int
+__lock_id_set(dbenv, cur_id, max_id)
+ DB_ENV *dbenv;
+ u_int32_t cur_id, max_id;
+{
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(cur_id, 0);
+ COMPQUIET(max_id, 0);
+ return (0);
+}
diff --git a/db/lock/lock_timer.c b/db/lock/lock_timer.c
index 11ccd3036..f81471f1e 100644
--- a/db/lock/lock_timer.c
+++ b/db/lock/lock_timer.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_timer.c,v 12.6 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_timer.c,v 12.13 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"
@@ -13,28 +12,30 @@
#include "dbinc/lock.h"
/*
- * __lock_set_timeout
- * -- set timeout values in shared memory.
+ * __lock_set_timeout --
+ * Set timeout values in shared memory.
*
* This is called from the transaction system. We either set the time that
* this transaction expires or the amount of time a lock for this transaction
* is permitted to wait.
*
- * PUBLIC: int __lock_set_timeout __P(( DB_ENV *,
- * PUBLIC: u_int32_t, db_timeout_t, u_int32_t));
+ * PUBLIC: int __lock_set_timeout __P((DB_ENV *,
+ * PUBLIC: DB_LOCKER *, db_timeout_t, u_int32_t));
*/
int
__lock_set_timeout(dbenv, locker, timeout, op)
DB_ENV *dbenv;
- u_int32_t locker;
+ DB_LOCKER *locker;
db_timeout_t timeout;
u_int32_t op;
{
int ret;
- LOCK_SYSTEM_LOCK(dbenv);
+ if (locker == NULL)
+ return (0);
+ LOCK_REGION_LOCK(dbenv);
ret = __lock_set_timeout_internal(dbenv, locker, timeout, op);
- LOCK_SYSTEM_UNLOCK(dbenv);
+ LOCK_REGION_UNLOCK(dbenv);
return (ret);
}
@@ -47,45 +48,33 @@ __lock_set_timeout(dbenv, locker, timeout, op)
* for this transaction is permitted to wait.
*
* PUBLIC: int __lock_set_timeout_internal
- * PUBLIC: __P((DB_ENV *, u_int32_t, db_timeout_t, u_int32_t));
+ * PUBLIC: __P((DB_ENV *, DB_LOCKER *, db_timeout_t, u_int32_t));
*/
int
-__lock_set_timeout_internal(dbenv, locker, timeout, op)
+__lock_set_timeout_internal(dbenv, sh_locker, timeout, op)
DB_ENV *dbenv;
- u_int32_t locker;
+ DB_LOCKER *sh_locker;
db_timeout_t timeout;
u_int32_t op;
{
- DB_LOCKER *sh_locker;
DB_LOCKREGION *region;
- DB_LOCKTAB *lt;
- u_int32_t locker_ndx;
- int ret;
-
- lt = dbenv->lk_handle;
- region = lt->reginfo.primary;
-
- LOCKER_LOCK(lt, region, locker, locker_ndx);
- ret = __lock_getlocker(lt, locker, locker_ndx, 1, &sh_locker);
-
- if (ret != 0)
- return (ret);
+ region = dbenv->lk_handle->reginfo.primary;
if (op == DB_SET_TXN_TIMEOUT) {
if (timeout == 0)
- LOCK_SET_TIME_INVALID(&sh_locker->tx_expire);
+ timespecclear(&sh_locker->tx_expire);
else
__lock_expires(dbenv, &sh_locker->tx_expire, timeout);
} else if (op == DB_SET_LOCK_TIMEOUT) {
sh_locker->lk_timeout = timeout;
F_SET(sh_locker, DB_LOCKER_TIMEOUT);
} else if (op == DB_SET_TXN_NOW) {
- LOCK_SET_TIME_INVALID(&sh_locker->tx_expire);
+ timespecclear(&sh_locker->tx_expire);
__lock_expires(dbenv, &sh_locker->tx_expire, 0);
sh_locker->lk_expire = sh_locker->tx_expire;
- if (!LOCK_TIME_ISVALID(&region->next_timeout) ||
- LOCK_TIME_GREATER(
- &region->next_timeout, &sh_locker->lk_expire))
+ if (!timespecisset(&region->next_timeout) ||
+ timespeccmp(
+ &region->next_timeout, &sh_locker->lk_expire, >))
region->next_timeout = sh_locker->lk_expire;
} else
return (EINVAL);
@@ -100,105 +89,86 @@ __lock_set_timeout_internal(dbenv, locker, timeout, op)
* return EINVAL if the parent does not exist or did not
* have a current txn timeout set.
*
- * PUBLIC: int __lock_inherit_timeout __P(( DB_ENV *, u_int32_t, u_int32_t));
+ * PUBLIC: int __lock_inherit_timeout __P((DB_ENV *, DB_LOCKER *, DB_LOCKER *));
*/
int
__lock_inherit_timeout(dbenv, parent, locker)
DB_ENV *dbenv;
- u_int32_t parent, locker;
+ DB_LOCKER *parent, *locker;
{
- DB_LOCKER *parent_locker, *sh_locker;
- DB_LOCKREGION *region;
- DB_LOCKTAB *lt;
- u_int32_t locker_ndx;
int ret;
- lt = dbenv->lk_handle;
- region = lt->reginfo.primary;
ret = 0;
- LOCK_SYSTEM_LOCK(dbenv);
-
- /* If the parent does not exist, we are done. */
- LOCKER_LOCK(lt, region, parent, locker_ndx);
- if ((ret = __lock_getlocker(lt,
- parent, locker_ndx, 0, &parent_locker)) != 0)
- goto err;
+ LOCK_REGION_LOCK(dbenv);
/*
* If the parent is not there yet, thats ok. If it
* does not have any timouts set, then avoid creating
* the child locker at this point.
*/
- if (parent_locker == NULL ||
- (LOCK_TIME_ISVALID(&parent_locker->tx_expire) &&
- !F_ISSET(parent_locker, DB_LOCKER_TIMEOUT))) {
+ if (parent == NULL ||
+ (timespecisset(&parent->tx_expire) &&
+ !F_ISSET(parent, DB_LOCKER_TIMEOUT))) {
ret = EINVAL;
- goto done;
- }
-
- LOCKER_LOCK(lt, region, locker, locker_ndx);
- if ((ret = __lock_getlocker(lt,
- locker, locker_ndx, 1, &sh_locker)) != 0)
goto err;
+ }
- sh_locker->tx_expire = parent_locker->tx_expire;
+ locker->tx_expire = parent->tx_expire;
- if (F_ISSET(parent_locker, DB_LOCKER_TIMEOUT)) {
- sh_locker->lk_timeout = parent_locker->lk_timeout;
- F_SET(sh_locker, DB_LOCKER_TIMEOUT);
- if (!LOCK_TIME_ISVALID(&parent_locker->tx_expire))
+ if (F_ISSET(parent, DB_LOCKER_TIMEOUT)) {
+ locker->lk_timeout = parent->lk_timeout;
+ F_SET(locker, DB_LOCKER_TIMEOUT);
+ if (!timespecisset(&parent->tx_expire))
ret = EINVAL;
}
-done:
-err: LOCK_SYSTEM_UNLOCK(dbenv);
+err: LOCK_REGION_UNLOCK(dbenv);
return (ret);
}
/*
* __lock_expires --
- * Set the expire time given the time to live. If timevalp is set then
- * it contains "now". This avoids repeated system calls to get the time.
+ * Set the expire time given the time to live.
*
- * PUBLIC: void __lock_expires __P((DB_ENV *, db_timeval_t *, db_timeout_t));
+ * PUBLIC: void __lock_expires __P((DB_ENV *, db_timespec *, db_timeout_t));
*/
void
-__lock_expires(dbenv, timevalp, timeout)
+__lock_expires(dbenv, timespecp, timeout)
DB_ENV *dbenv;
- db_timeval_t *timevalp;
+ db_timespec *timespecp;
db_timeout_t timeout;
{
- if (!LOCK_TIME_ISVALID(timevalp))
- __os_clock(dbenv, &timevalp->tv_sec, &timevalp->tv_usec);
- if (timeout > 1000000) {
- timevalp->tv_sec += timeout / 1000000;
- timevalp->tv_usec += timeout % 1000000;
- } else
- timevalp->tv_usec += timeout;
+ db_timespec v;
- if (timevalp->tv_usec > 1000000) {
- timevalp->tv_sec++;
- timevalp->tv_usec -= 1000000;
- }
+ /*
+ * If timespecp is set then it contains "now". This avoids repeated
+ * system calls to get the time.
+ */
+ if (!timespecisset(timespecp))
+ __os_gettime(dbenv, timespecp);
+
+ /* Convert the microsecond timeout argument to a timespec. */
+ DB_TIMEOUT_TO_TIMESPEC(timeout, &v);
+
+ /* Add the timeout to "now". */
+ timespecadd(timespecp, &v);
}
/*
* __lock_expired -- determine if a lock has expired.
*
- * PUBLIC: int __lock_expired __P((DB_ENV *, db_timeval_t *, db_timeval_t *));
+ * PUBLIC: int __lock_expired __P((DB_ENV *, db_timespec *, db_timespec *));
*/
int
-__lock_expired(dbenv, now, timevalp)
+__lock_expired(dbenv, now, timespecp)
DB_ENV *dbenv;
- db_timeval_t *now, *timevalp;
+ db_timespec *now, *timespecp;
{
- if (!LOCK_TIME_ISVALID(timevalp))
+ if (!timespecisset(timespecp))
return (0);
- if (!LOCK_TIME_ISVALID(now))
- __os_clock(dbenv, &now->tv_sec, &now->tv_usec);
+ if (!timespecisset(now))
+ __os_gettime(dbenv, now);
- return (now->tv_sec > timevalp->tv_sec ||
- (now->tv_sec == timevalp->tv_sec &&
- now->tv_usec >= timevalp->tv_usec));
+ return (timespeccmp(now, timespecp, >=));
}
diff --git a/db/lock/lock_util.c b/db/lock/lock_util.c
index be5d18626..b12b62ffa 100644
--- a/db/lock/lock_util.c
+++ b/db/lock/lock_util.c
@@ -1,10 +1,9 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996-2006
- * Oracle Corporation. All rights reserved.
+ * Copyright (c) 1996,2007 Oracle. All rights reserved.
*
- * $Id: lock_util.c,v 12.7 2006/08/24 14:46:11 bostic Exp $
+ * $Id: lock_util.c,v 12.9 2007/05/17 15:15:43 bostic Exp $
*/
#include "db_config.h"