#include "db_config.h"
#include "db_int.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
int
__lock_id_pp(dbenv, idp)
DB_ENV *dbenv;
u_int32_t *idp;
{
DB_THREAD_INFO *ip;
int ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lk_handle, "DB_ENV->lock_id", DB_INIT_LOCK);
ENV_ENTER(dbenv, ip);
REPLICATION_WRAP(dbenv, (__lock_id(dbenv, idp, NULL)), ret);
ENV_LEAVE(dbenv, ip);
return (ret);
}
int
__lock_id(dbenv, idp, lkp)
DB_ENV *dbenv;
u_int32_t *idp;
DB_LOCKER **lkp;
{
DB_LOCKER *lk;
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
u_int32_t id, *ids;
int nids, ret;
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
ret = 0;
id = DB_LOCK_INVALIDID;
lk = NULL;
LOCK_SYSTEM_LOCK(dbenv);
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;
if (region->stat.st_id == region->stat.st_cur_maxid) {
if ((ret = __os_malloc(dbenv,
sizeof(u_int32_t) * region->stat.st_nlockers, &ids)) != 0)
goto err;
nids = 0;
SH_TAILQ_FOREACH(lk, ®ion->lockers, ulinks, __db_locker)
ids[nids++] = lk->id;
region->stat.st_id = DB_LOCK_INVALIDID;
region->stat.st_cur_maxid = DB_LOCK_MAXID;
if (nids != 0)
__db_idspace(ids, nids,
®ion->stat.st_id, ®ion->stat.st_cur_maxid);
__os_free(dbenv, ids);
}
id = ++region->stat.st_id;
ret = __lock_getlocker_int(lt, id, 1, &lk);
err: LOCK_SYSTEM_UNLOCK(dbenv);
UNLOCK_LOCKERS(dbenv, region);
if (idp)
*idp = id;
if (lkp)
*lkp = lk;
return (ret);
}
void
__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;
}
int
__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 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);
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);
}
int
__lock_id_free(dbenv, sh_locker)
DB_ENV *dbenv;
DB_LOCKER *sh_locker;
{
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
int ret;
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
ret = 0;
if (sh_locker->nlocks != 0) {
__db_errx(dbenv, "Locker still has locks");
ret = EINVAL;
goto err;
}
LOCK_SYSTEM_LOCK(dbenv);
LOCK_LOCKERS(dbenv, region);
ret = __lock_freelocker(lt, region, sh_locker);
UNLOCK_LOCKERS(dbenv, region);
LOCK_SYSTEM_UNLOCK(dbenv);
err:
return (ret);
}
int
__lock_id_set(dbenv, cur_id, max_id)
DB_ENV *dbenv;
u_int32_t cur_id, max_id;
{
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lk_handle, "lock_id_set", DB_INIT_LOCK);
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
region->stat.st_id = cur_id;
region->stat.st_cur_maxid = max_id;
return (0);
}
int
__lock_getlocker(lt, locker, create, retp)
DB_LOCKTAB *lt;
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);
SH_TAILQ_FOREACH(sh_locker, <->locker_tab[indx], links, __db_locker)
if (sh_locker->id == locker)
break;
if (sh_locker == NULL && create) {
if ((sh_locker = SH_TAILQ_FIRST(
®ion->free_lockers, __db_locker)) == NULL)
return (__lock_nomem(dbenv, "locker entries"));
SH_TAILQ_REMOVE(
®ion->free_lockers, sh_locker, links, __db_locker);
++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);
sh_locker->dd_id = 0;
sh_locker->master_locker = INVALID_ROFF;
sh_locker->parent_locker = INVALID_ROFF;
SH_LIST_INIT(&sh_locker->child_locker);
sh_locker->flags = 0;
SH_LIST_INIT(&sh_locker->heldby);
sh_locker->nlocks = 0;
sh_locker->nwrites = 0;
sh_locker->lk_timeout = 0;
timespecclear(&sh_locker->tx_expire);
timespecclear(&sh_locker->lk_expire);
SH_TAILQ_INSERT_HEAD(
<->locker_tab[indx], sh_locker, links, __db_locker);
SH_TAILQ_INSERT_HEAD(®ion->lockers,
sh_locker, ulinks, __db_locker);
}
*retp = sh_locker;
return (0);
}
int
__lock_addfamilylocker(dbenv, pid, id)
DB_ENV *dbenv;
u_int32_t pid, id;
{
DB_LOCKER *lockerp, *mlockerp;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
int ret;
COMPQUIET(region, NULL);
lt = dbenv->lk_handle;
region = lt->reginfo.primary;
LOCK_SYSTEM_LOCK(dbenv);
LOCK_LOCKERS(dbenv, region);
if ((ret = __lock_getlocker_int(lt, pid, 1, &mlockerp)) != 0)
goto err;
if ((ret = __lock_getlocker_int(lt, id, 1, &lockerp)) != 0)
goto err;
lockerp->parent_locker = R_OFFSET(<->reginfo, mlockerp);
if (mlockerp->master_locker == INVALID_ROFF)
lockerp->master_locker = R_OFFSET(<->reginfo, mlockerp);
else {
lockerp->master_locker = mlockerp->master_locker;
mlockerp = R_ADDR(<->reginfo, mlockerp->master_locker);
}
SH_LIST_INSERT_HEAD(
&mlockerp->child_locker, lockerp, child_link, __db_locker);
err: LOCK_SYSTEM_UNLOCK(dbenv);
UNLOCK_LOCKERS(dbenv, region);
return (ret);
}
int
__lock_freefamilylocker(lt, sh_locker)
DB_LOCKTAB *lt;
DB_LOCKER *sh_locker;
{
DB_ENV *dbenv;
DB_LOCKREGION *region;
int ret;
dbenv = lt->dbenv;
region = lt->reginfo.primary;
if (sh_locker == NULL)
return (0);
LOCK_SYSTEM_LOCK(dbenv);
LOCK_LOCKERS(dbenv, region);
if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) {
ret = EINVAL;
__db_errx(dbenv, "Freeing locker with locks");
goto err;
}
if (sh_locker->master_locker != INVALID_ROFF)
SH_LIST_REMOVE(sh_locker, child_link, __db_locker);
ret = __lock_freelocker(lt, region, sh_locker);
err: LOCK_SYSTEM_UNLOCK(dbenv);
UNLOCK_LOCKERS(dbenv, region);
return (ret);
}
int
__lock_freelocker(lt, region, sh_locker)
DB_LOCKTAB *lt;
DB_LOCKREGION *region;
DB_LOCKER *sh_locker;
{
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);
}