diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2007-07-30 11:58:31 +0300 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2007-07-30 11:58:31 +0300 |
commit | cab228435bde1b5496522c03a4ce9840f2ef3701 (patch) | |
tree | 2c37b65d176e2de097603333f4de071c31eeff3d /db/lock | |
parent | 2d07882d45e9e575c00f8f402d4c7271bb65cfe9 (diff) | |
download | rpm-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.c | 451 | ||||
-rw-r--r-- | db/lock/lock_conflict.c | 34 | ||||
-rw-r--r-- | db/lock/lock_deadlock.c | 231 | ||||
-rw-r--r-- | db/lock/lock_failchk.c | 14 | ||||
-rw-r--r-- | db/lock/lock_id.c | 170 | ||||
-rw-r--r-- | db/lock/lock_list.c | 10 | ||||
-rw-r--r-- | db/lock/lock_method.c | 33 | ||||
-rw-r--r-- | db/lock/lock_region.c | 140 | ||||
-rw-r--r-- | db/lock/lock_stat.c | 158 | ||||
-rw-r--r-- | db/lock/lock_stub.c | 491 | ||||
-rw-r--r-- | db/lock/lock_timer.c | 144 | ||||
-rw-r--r-- | db/lock/lock_util.c | 5 |
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(®ion->next_timeout))) + (region->need_dd || timespecisset(®ion->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(<->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(<->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(®ion->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(®ion->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(<->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(<->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(®ion->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(<->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(<->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(®ion->next_timeout) || - LOCK_TIME_GREATER( - ®ion->next_timeout, &sh_locker->lk_expire))) + if (timespecisset(&sh_locker->lk_expire) && + (!timespecisset(®ion->next_timeout) || + timespeccmp( + ®ion->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(<->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(®ion->next_timeout))) + (region->need_dd || timespecisset(®ion->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(<->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(<->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( <->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(<->reginfo, + __env_alloc_free(<->reginfo, SH_DBT_PTR(&sh_obj->lockobj)); SH_TAILQ_INSERT_HEAD( ®ion->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(<->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( ®ion->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, <->obj_tab[ndx], links, __db_lockobj) + SH_TAILQ_FOREACH(sh_obj, <->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(®ion->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(<->reginfo, obj->size, 0, &p)) != 0) { + __env_alloc(<->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( ®ion->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(<->reginfo, parent->parent_locker); - if (parent->id == locker) + if (parent->parent_locker == l_off) return (1); + parent = R_ADDR(<->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(<->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(<->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(<->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(®ion->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( ®ion->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(<->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(<->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(<->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(®ion->next_timeout) || + (!timespecisset(®ion->next_timeout) || !__lock_expired(dbenv, &now, ®ion->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, ®ion->dd_objs, dd_links, __db_lockobj) +skip: LOCK_OBJECTS(dbenv, region); + op = SH_TAILQ_FIRST(®ion->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(<->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, ®ion->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, ®ion->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(®ion->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(<->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(<->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(<->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(<->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(<->reginfo, lp); *bmp = bitmap; *allocp = nentries; __os_free(dbenv, tmpmap); -done: if (LOCK_TIME_ISVALID(®ion->next_timeout)) { - if (LOCK_TIME_ISMAX(&min_timeout)) - LOCK_SET_TIME_INVALID(®ion->next_timeout); - else - region->next_timeout = min_timeout; - } +done: if (timespecisset(®ion->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(<->reginfo, lockp) != info->last_lock || - lockp->holder != lockerp->id || + lockp->holder != R_OFFSET(<->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(®ion->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( ®ion->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( <->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(<->locker_tab[indx], sh_locker, links, __db_locker); SH_TAILQ_INSERT_HEAD( ®ion->free_lockers, sh_locker, links, __db_locker); SH_TAILQ_REMOVE(®ion->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(<->reginfo, REGION_CREATE_OK); size = __lock_region_size(dbenv); - if ((ret = __db_r_attach(dbenv, <->reginfo, size)) != 0) + if ((ret = __env_region_attach(dbenv, <->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(<->reginfo, region->conf_off); lt->obj_tab = R_ADDR(<->reginfo, region->obj_off); + lt->obj_stat = R_ADDR(<->reginfo, region->stat_off); +#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER + lt->obj_mtx = R_ADDR(<->reginfo, region->mtx_off); +#endif lt->locker_tab = R_ADDR(<->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, <->reginfo, 0); + } + (void)__env_region_detach(dbenv, <->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(<->reginfo, - sizeof(DB_LOCKREGION), 0, <->reginfo.primary)) != 0) + if ((ret = __env_alloc(<->reginfo, + sizeof(DB_LOCKREGION), <->reginfo.primary)) != 0) goto mem_err; lt->reginfo.rp->primary = R_OFFSET(<->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(®ion->next_timeout); + timespecclear(®ion->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( - <->reginfo, (size_t)(lk_modes * lk_modes), 0, &addr)) != 0) + if ((ret = __env_alloc( + <->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(<->reginfo, addr); /* Allocate room for the object hash table and initialize it. */ - if ((ret = __db_shalloc(<->reginfo, - region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0) + if ((ret = __env_alloc(<->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(<->reginfo, addr); + /* Allocate room for the object hash stats table and initialize it. */ + if ((ret = __env_alloc(<->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(<->reginfo, addr); +#ifdef HAVE_FINE_GRAINED_LOCK_MANAGER + if ((ret = __env_alloc(<->reginfo, + region->object_t_size * sizeof(db_mutex_t), &mtxp)) != 0) + goto mem_err; + region->mtx_off = R_OFFSET(<->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, ®ion->mtx_objs)) != 0) + return (ret); + + if ((ret = __mutex_alloc( + dbenv, MTX_LOCK_REGION, 0, ®ion->mtx_locks)) != 0) + return (ret); + + if ((ret = __mutex_alloc( + dbenv, MTX_LOCK_REGION, 0, ®ion->mtx_lockers)) != 0) + return (ret); + +#endif /* Allocate room for the locker hash table and initialize it. */ - if ((ret = __db_shalloc(<->reginfo, - region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0) + if ((ret = __env_alloc(<->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(<->reginfo, addr); @@ -230,8 +267,8 @@ __lock_region_init(dbenv, lt) /* Initialize locks onto a free list. */ SH_TAILQ_INIT(®ion->free_locks); for (i = 0; i < region->stat.st_maxlocks; ++i) { - if ((ret = __db_shalloc(<->reginfo, - sizeof(struct __db_lock), 0, &lp)) != 0) + if ((ret = __env_alloc(<->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(®ion->dd_objs); SH_TAILQ_INIT(®ion->free_objs); for (i = 0; i < region->stat.st_maxobjects; ++i) { - if ((ret = __db_shalloc(<->reginfo, - sizeof(DB_LOCKOBJ), 0, &op)) != 0) + if ((ret = __env_alloc(<->reginfo, + sizeof(DB_LOCKOBJ), &op)) != 0) goto mem_err; SH_TAILQ_INSERT_HEAD( ®ion->free_objs, op, links, __db_lockobj); + op->generation = 0; } /* Initialize lockers onto a free list. */ SH_TAILQ_INIT(®ion->lockers); SH_TAILQ_INIT(®ion->free_lockers); for (i = 0; i < region->stat.st_maxlockers; ++i) { - if ((ret = __db_shalloc(<->reginfo, - sizeof(DB_LOCKER), 0, &lidp)) != 0) { + if ((ret = + __env_alloc(<->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, ®ion->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(<->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(®ion->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(<->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, <->reginfo, "Lock"); + LOCK_REGION_LOCK(dbenv); + __db_print_reginfo(dbenv, <->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(<->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(®ion->next_timeout) || - LOCK_TIME_GREATER( - ®ion->next_timeout, &sh_locker->lk_expire)) + if (!timespecisset(®ion->next_timeout) || + timespeccmp( + ®ion->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" |