#include "db_config.h"
#include "db_int.h"
#include "dbinc/lock.h"
static int __lock_region_init __P((ENV *, DB_LOCKTAB *));
#define DB_LOCK_RIW_N 9
static const u_int8_t db_riw_conflicts[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 1, 1,
0, 0, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 0, 0, 0, 0, 1, 1,
0, 0, 1, 0, 1, 0, 1, 0, 0,
0, 1, 1, 0, 1, 1, 1, 0, 1
};
#define DB_LOCK_CDB_N 5
static const u_int8_t db_cdb_conflicts[] = {
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 0, 1, 0, 1
};
int
__lock_open(env)
ENV *env;
{
DB_ENV *dbenv;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
int region_locked, ret;
dbenv = env->dbenv;
region_locked = 0;
if ((ret = __os_calloc(env, 1, sizeof(DB_LOCKTAB), <)) != 0)
return (ret);
lt->env = env;
if ((ret = __env_region_share(env, <->reginfo)) != 0)
goto err;
if (F_ISSET(<->reginfo, REGION_CREATE))
if ((ret = __lock_region_init(env, lt)) != 0)
goto err;
region = lt->reginfo.primary =
R_ADDR(<->reginfo, ((REGENV *)env->reginfo->primary)->lt_primary);
lt->conflicts = R_ADDR(<->reginfo, region->conf_off);
lt->obj_tab = R_ADDR(<->reginfo, region->obj_off);
#ifdef HAVE_STATISTICS
lt->obj_stat = R_ADDR(<->reginfo, region->stat_off);
#endif
lt->part_array = R_ADDR(<->reginfo, region->part_off);
lt->locker_tab = R_ADDR(<->reginfo, region->locker_off);
env->lk_handle = lt;
lt->reginfo.mtx_alloc = region->mtx_region;
LOCK_REGION_LOCK(env);
region_locked = 1;
if (dbenv->lk_detect != DB_LOCK_NORUN) {
if (region->detect != DB_LOCK_NORUN &&
dbenv->lk_detect != DB_LOCK_DEFAULT &&
region->detect != dbenv->lk_detect) {
__db_errx(env, DB_STR("2041",
"lock_open: incompatible deadlock detector mode"));
ret = EINVAL;
goto err;
}
if (region->detect == DB_LOCK_NORUN)
region->detect = dbenv->lk_detect;
}
if (dbenv->lk_timeout != 0)
region->lk_timeout = dbenv->lk_timeout;
if (dbenv->tx_timeout != 0)
region->tx_timeout = dbenv->tx_timeout;
LOCK_REGION_UNLOCK(env);
region_locked = 0;
return (0);
err: if (lt->reginfo.addr != NULL) {
if (region_locked)
LOCK_REGION_UNLOCK(env);
(void)__env_region_detach(env, <->reginfo, 0);
}
env->lk_handle = NULL;
__os_free(env, lt);
return (ret);
}
static int
__lock_region_init(env, lt)
ENV *env;
DB_LOCKTAB *lt;
{
const u_int8_t *lk_conflicts;
struct __db_lock *lp;
DB_ENV *dbenv;
DB_LOCKER *lidp;
DB_LOCKOBJ *op;
DB_LOCKREGION *region;
DB_LOCKPART *part;
u_int32_t extra_locks, extra_objects, i, j, max;
u_int8_t *addr;
int lk_modes, ret;
dbenv = env->dbenv;
if ((ret = __env_alloc(<->reginfo,
sizeof(DB_LOCKREGION), <->reginfo.primary)) != 0)
goto mem_err;
((REGENV *)env->reginfo->primary)->lt_primary =
R_OFFSET(<->reginfo, lt->reginfo.primary);
region = lt->reginfo.primary;
memset(region, 0, sizeof(*region));
region->mtx_region = ((REGENV *)env->reginfo->primary)->mtx_regenv;
if (dbenv->lk_modes == 0)
if (CDB_LOCKING(env)) {
lk_modes = DB_LOCK_CDB_N;
lk_conflicts = db_cdb_conflicts;
} else {
lk_modes = DB_LOCK_RIW_N;
lk_conflicts = db_riw_conflicts;
}
else {
lk_modes = dbenv->lk_modes;
lk_conflicts = dbenv->lk_conflicts;
}
region->need_dd = 0;
timespecclear(®ion->next_timeout);
region->detect = DB_LOCK_NORUN;
region->lk_timeout = dbenv->lk_timeout;
region->tx_timeout = dbenv->tx_timeout;
region->locker_t_size = dbenv->locker_t_size;
region->object_t_size = dbenv->object_t_size;
region->part_t_size = dbenv->lk_partitions;
region->lock_id = 0;
region->cur_maxid = DB_LOCK_MAXID;
region->nmodes = lk_modes;
memset(®ion->stat, 0, sizeof(region->stat));
region->stat.st_maxlocks = dbenv->lk_max;
region->stat.st_maxlockers = dbenv->lk_max_lockers;
region->stat.st_maxobjects = dbenv->lk_max_objects;
region->stat.st_initlocks = region->stat.st_locks = dbenv->lk_init;
region->stat.st_initlockers =
region->stat.st_lockers = dbenv->lk_init_lockers;
region->stat.st_initobjects =
region->stat.st_objects = dbenv->lk_init_objects;
region->stat.st_partitions = dbenv->lk_partitions;
region->stat.st_tablesize = dbenv->object_t_size;
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);
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);
#ifdef HAVE_STATISTICS
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);
#endif
if ((ret = __env_alloc(<->reginfo,
region->part_t_size * sizeof(DB_LOCKPART), &part)) != 0)
goto mem_err;
memset(part, 0, region->part_t_size * sizeof(DB_LOCKPART));
region->part_off = R_OFFSET(<->reginfo, part);
for (i = 0; i < region->part_t_size; i++) {
if ((ret = __mutex_alloc(
env, MTX_LOCK_REGION, 0, &part[i].mtx_part)) != 0)
return (ret);
}
if ((ret = __mutex_alloc(
env, MTX_LOCK_REGION, 0, ®ion->mtx_dd)) != 0)
return (ret);
if ((ret = __mutex_alloc(
env, MTX_LOCK_REGION, 0, ®ion->mtx_lockers)) != 0)
return (ret);
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);
SH_TAILQ_INIT(®ion->dd_objs);
extra_locks = region->stat.st_locks -
((region->stat.st_locks / region->part_t_size) *
region->part_t_size);
extra_objects = region->stat.st_objects -
((region->stat.st_objects / region->part_t_size) *
region->part_t_size);
for (j = 0; j < region->part_t_size; j++) {
SH_TAILQ_INIT(&part[j].free_locks);
max = region->stat.st_locks / region->part_t_size;
if (extra_locks > 0) {
max++;
extra_locks--;
}
if ((ret =
__env_alloc(<->reginfo,
sizeof(struct __db_lock) * max,
&lp)) != 0)
goto mem_err;
part[j].lock_mem_off = R_OFFSET(<->reginfo, lp);
for (i = 0; i < max; ++i) {
memset(lp, 0, sizeof(*lp));
lp->status = DB_LSTAT_FREE;
SH_TAILQ_INSERT_HEAD(
&part[j].free_locks, lp, links, __db_lock);
++lp;
}
max = region->stat.st_objects / region->part_t_size;
if (extra_objects > 0) {
max++;
extra_objects--;
}
SH_TAILQ_INIT(&part[j].free_objs);
if ((ret =
__env_alloc(<->reginfo,
sizeof(DB_LOCKOBJ) * max,
&op)) != 0)
goto mem_err;
part[j].lockobj_mem_off = R_OFFSET(<->reginfo, op);
for (i = 0; i < max; ++i) {
memset(op, 0, sizeof(*op));
SH_TAILQ_INSERT_HEAD(
&part[j].free_objs, op, links, __db_lockobj);
++op;
}
}
SH_TAILQ_INIT(®ion->lockers);
SH_TAILQ_INIT(®ion->free_lockers);
if ((ret =
__env_alloc(<->reginfo,
sizeof(DB_LOCKER) * region->stat.st_lockers,
&lidp)) != 0)
goto mem_err;
region->locker_mem_off = R_OFFSET(<->reginfo, lidp);
for (i = 0; i < region->stat.st_lockers; ++i) {
SH_TAILQ_INSERT_HEAD(
®ion->free_lockers, lidp, links, __db_locker);
++lidp;
}
return (0);
mem_err: __db_errx(env, DB_STR("2042",
"unable to allocate memory for the lock table"));
return (ret);
}
int
__lock_env_refresh(env)
ENV *env;
{
DB_LOCKREGION *lr;
DB_LOCKTAB *lt;
REGINFO *reginfo;
u_int32_t j;
int ret;
lt = env->lk_handle;
reginfo = <->reginfo;
lr = reginfo->primary;
if (F_ISSET(env, ENV_PRIVATE)) {
reginfo->mtx_alloc = MUTEX_INVALID;
__env_alloc_free(reginfo, R_ADDR(reginfo, lr->conf_off));
__env_alloc_free(reginfo, R_ADDR(reginfo, lr->obj_off));
__env_alloc_free(reginfo, R_ADDR(reginfo, lr->locker_off));
__env_alloc_free(reginfo, R_ADDR(reginfo, lr->stat_off));
for (j = 0; j < lr->part_t_size; j++) {
SH_TAILQ_INIT(&FREE_OBJS(lt, j));
SH_TAILQ_INIT(&FREE_LOCKS(lt, j));
__env_alloc_free(reginfo,
R_ADDR(reginfo,
lt->part_array[j].lock_mem_off));
__env_alloc_free(reginfo,
R_ADDR(reginfo,
lt->part_array[j].lockobj_mem_off));
}
__env_alloc_free(reginfo, R_ADDR(reginfo, lr->part_off));
SH_TAILQ_INIT(&lr->free_lockers);
__env_alloc_free(reginfo,
R_ADDR(reginfo, lr->locker_mem_off));
}
ret = __env_region_detach(env, reginfo, 0);
__os_free(env, lt);
env->lk_handle = NULL;
return (ret);
}
u_int32_t
__lock_region_mutex_count(env)
ENV *env;
{
DB_ENV *dbenv;
dbenv = env->dbenv;
return (dbenv->lk_init_lockers + dbenv->lk_partitions + 3);
}
u_int32_t
__lock_region_mutex_max(env)
ENV *env;
{
DB_ENV *dbenv;
u_int32_t count;
dbenv = env->dbenv;
if ((count = dbenv->lk_max_lockers) == 0)
count = DB_LOCK_DEFAULT_N;
if (count > dbenv->lk_init_lockers)
return (count - dbenv->lk_init_lockers);
else
return (0);
}
size_t
__lock_region_max(env)
ENV *env;
{
DB_ENV *dbenv;
size_t retval;
u_int32_t count;
dbenv = env->dbenv;
retval = 0;
if ((count = dbenv->lk_max) == 0)
count = DB_LOCK_DEFAULT_N;
if (count > dbenv->lk_init)
retval += __env_alloc_size(sizeof(struct __db_lock)) *
(count - dbenv->lk_init);
if ((count = dbenv->lk_max_objects) == 0)
count = DB_LOCK_DEFAULT_N;
if (count > dbenv->lk_init_objects)
retval += __env_alloc_size(sizeof(DB_LOCKOBJ)) *
(count - dbenv->lk_init_objects);
if ((count = dbenv->lk_max_lockers) == 0)
count = DB_LOCK_DEFAULT_N;
if (count > dbenv->lk_init_lockers)
retval += __env_alloc_size(sizeof(DB_LOCKER)) *
(count - dbenv->lk_init_lockers);
retval += retval / 4;
return (retval);
}
size_t
__lock_region_size(env, other_alloc)
ENV *env;
size_t other_alloc;
{
DB_ENV *dbenv;
size_t retval;
u_int32_t count;
dbenv = env->dbenv;
if (dbenv->lk_init_objects < dbenv->lk_partitions * 5)
dbenv->lk_init_objects = dbenv->lk_partitions * 5;
if (dbenv->lk_init < dbenv->lk_partitions * 5)
dbenv->lk_init = dbenv->lk_partitions * 5;
retval = 0;
retval += __env_alloc_size(sizeof(DB_LOCKREGION));
retval += __env_alloc_size((size_t)(dbenv->lk_modes * dbenv->lk_modes));
if (dbenv->lk_max_lockers != 0)
dbenv->locker_t_size = __db_tablesize(dbenv->lk_max_lockers);
else if (dbenv->tx_max != 0)
dbenv->locker_t_size = __db_tablesize(dbenv->tx_max);
else {
if (dbenv->memory_max != 0)
count = (u_int32_t)
(((dbenv->memory_max - other_alloc) / 10) /
sizeof(DB_LOCKER));
else
count = DB_LOCK_DEFAULT_N / 10;
if (count < dbenv->lk_init_lockers)
count = dbenv->lk_init_lockers;
dbenv->locker_t_size = __db_tablesize(count);
}
retval += __env_alloc_size(dbenv->locker_t_size * (sizeof(DB_HASHTAB)));
retval += __env_alloc_size(sizeof(DB_LOCKER)) * dbenv->lk_init_lockers;
retval += __env_alloc_size(sizeof(struct __db_lock) * dbenv->lk_init);
other_alloc += retval;
if ((count = dbenv->lk_max_objects) == 0) {
if (dbenv->memory_max != 0)
count = (u_int32_t)(
((dbenv->memory_max - other_alloc) / 2)
/ sizeof(DB_LOCKOBJ));
else
count = DB_LOCK_DEFAULT_N;
if (count < dbenv->lk_init_objects)
count = dbenv->lk_init_objects;
}
count *= 2;
count += dbenv->lk_init_objects;
count /= 3;
if (dbenv->object_t_size == 0)
dbenv->object_t_size = __db_tablesize(count);
retval += __env_alloc_size(
__db_tablesize(dbenv->object_t_size) * (sizeof(DB_HASHTAB)));
#ifdef HAVE_STATISTICS
retval += __env_alloc_size(
__db_tablesize(dbenv->object_t_size) * (sizeof(DB_LOCK_HSTAT)));
#endif
retval +=
__env_alloc_size(dbenv->lk_partitions * (sizeof(DB_LOCKPART)));
retval += __env_alloc_size(sizeof(DB_LOCKOBJ) * dbenv->lk_init_objects);
return (retval);
}