#include "db_config.h"
#include "db_int.h"
#include "dbinc/mp.h"
#include "dbinc/db_page.h"
#include "dbinc/hash.h"
int
__memp_env_create(dbenv)
DB_ENV *dbenv;
{
dbenv->mp_bytes = dbenv->mp_max_bytes =
32 * ((8 * 1024) + sizeof(BH)) + 37 * sizeof(DB_MPOOL_HASH);
dbenv->mp_ncache = 1;
return (0);
}
void
__memp_env_destroy(dbenv)
DB_ENV *dbenv;
{
COMPQUIET(dbenv, NULL);
}
int
__memp_get_cachesize(dbenv, gbytesp, bytesp, ncachep)
DB_ENV *dbenv;
u_int32_t *gbytesp, *bytesp;
int *ncachep;
{
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_cachesize", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
mp = env->mp_handle->reginfo[0].primary;
if (gbytesp != NULL)
*gbytesp = mp->stat.st_gbytes;
if (bytesp != NULL)
*bytesp = mp->stat.st_bytes;
if (ncachep != NULL)
*ncachep = (int)mp->nreg;
} else {
if (gbytesp != NULL)
*gbytesp = dbenv->mp_gbytes;
if (bytesp != NULL)
*bytesp = dbenv->mp_bytes;
if (ncachep != NULL)
*ncachep = (int)dbenv->mp_ncache;
}
return (0);
}
int
__memp_set_cachesize(dbenv, gbytes, bytes, arg_ncache)
DB_ENV *dbenv;
u_int32_t gbytes, bytes;
int arg_ncache;
{
ENV *env;
u_int ncache;
env = dbenv->env;
ncache = arg_ncache <= 0 ? 1 : (u_int)arg_ncache;
if (sizeof(roff_t) == 4 && gbytes / ncache == 4 && bytes == 0) {
--gbytes;
bytes = GIGABYTE - 1;
} else {
gbytes += bytes / GIGABYTE;
bytes %= GIGABYTE;
}
if (!F_ISSET(env, ENV_OPEN_CALLED)) {
if (sizeof(roff_t) <= 4 && gbytes / ncache >= 4) {
__db_errx(env,
"individual cache size too large: maximum is 4GB");
return (EINVAL);
}
if (gbytes / ncache > 10000) {
__db_errx(env,
"individual cache size too large: maximum is 10TB");
return (EINVAL);
}
}
if (gbytes == 0) {
if (bytes < 500 * MEGABYTE)
bytes += (bytes / 4) + 37 * sizeof(DB_MPOOL_HASH);
if (bytes / ncache < DB_CACHESIZE_MIN)
bytes = ncache * DB_CACHESIZE_MIN;
}
if (F_ISSET(env, ENV_OPEN_CALLED))
return (__memp_resize(env->mp_handle, gbytes, bytes));
dbenv->mp_gbytes = gbytes;
dbenv->mp_bytes = bytes;
dbenv->mp_ncache = ncache;
return (0);
}
int
__memp_set_config(dbenv, which, on)
DB_ENV *dbenv;
u_int32_t which;
int on;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->memp_set_config", DB_INIT_MPOOL);
switch (which) {
case DB_MEMP_SUPPRESS_WRITE:
case DB_MEMP_SYNC_INTERRUPT:
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
if (on)
FLD_SET(mp->config_flags, which);
else
FLD_CLR(mp->config_flags, which);
}
break;
default:
return (EINVAL);
}
return (0);
}
int
__memp_get_config(dbenv, which, onp)
DB_ENV *dbenv;
u_int32_t which;
int *onp;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_REQUIRES_CONFIG(env,
env->mp_handle, "DB_ENV->memp_get_config", DB_INIT_MPOOL);
switch (which) {
case DB_MEMP_SUPPRESS_WRITE:
case DB_MEMP_SYNC_INTERRUPT:
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
*onp = FLD_ISSET(mp->config_flags, which) ? 1 : 0;
} else
*onp = 0;
break;
default:
return (EINVAL);
}
return (0);
}
int
__memp_get_mp_max_openfd(dbenv, maxopenfdp)
DB_ENV *dbenv;
int *maxopenfdp;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_mp_max_openfd", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
*maxopenfdp = mp->mp_maxopenfd;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else
*maxopenfdp = dbenv->mp_maxopenfd;
return (0);
}
int
__memp_set_mp_max_openfd(dbenv, maxopenfd)
DB_ENV *dbenv;
int maxopenfd;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->set_mp_max_openfd", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
mp->mp_maxopenfd = maxopenfd;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else
dbenv->mp_maxopenfd = maxopenfd;
return (0);
}
int
__memp_get_mp_max_write(dbenv, maxwritep, maxwrite_sleepp)
DB_ENV *dbenv;
int *maxwritep;
db_timeout_t *maxwrite_sleepp;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
*maxwritep = mp->mp_maxwrite;
*maxwrite_sleepp = mp->mp_maxwrite_sleep;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else {
*maxwritep = dbenv->mp_maxwrite;
*maxwrite_sleepp = dbenv->mp_maxwrite_sleep;
}
return (0);
}
int
__memp_set_mp_max_write(dbenv, maxwrite, maxwrite_sleep)
DB_ENV *dbenv;
int maxwrite;
db_timeout_t maxwrite_sleep;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
mp->mp_maxwrite = maxwrite;
mp->mp_maxwrite_sleep = maxwrite_sleep;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else {
dbenv->mp_maxwrite = maxwrite;
dbenv->mp_maxwrite_sleep = maxwrite_sleep;
}
return (0);
}
int
__memp_get_mp_mmapsize(dbenv, mp_mmapsizep)
DB_ENV *dbenv;
size_t *mp_mmapsizep;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
*mp_mmapsizep = mp->mp_mmapsize;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else
*mp_mmapsizep = dbenv->mp_mmapsize;
return (0);
}
int
__memp_set_mp_mmapsize(dbenv, mp_mmapsize)
DB_ENV *dbenv;
size_t mp_mmapsize;
{
DB_MPOOL *dbmp;
DB_THREAD_INFO *ip;
ENV *env;
MPOOL *mp;
env = dbenv->env;
ENV_NOT_CONFIGURED(env,
env->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);
if (MPOOL_ON(env)) {
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
ENV_ENTER(env, ip);
MPOOL_SYSTEM_LOCK(env);
mp->mp_mmapsize = mp_mmapsize;
MPOOL_SYSTEM_UNLOCK(env);
ENV_LEAVE(env, ip);
} else
dbenv->mp_mmapsize = mp_mmapsize;
return (0);
}
int
__memp_nameop(env, fileid, newname, fullold, fullnew, inmem)
ENV *env;
u_int8_t *fileid;
const char *newname, *fullold, *fullnew;
int inmem;
{
DB_MPOOL *dbmp;
DB_MPOOL_HASH *hp, *nhp;
MPOOL *mp;
MPOOLFILE *mfp;
roff_t newname_off;
u_int32_t bucket;
int locked, ret;
size_t nlen;
void *p;
#undef op_is_remove
#define op_is_remove (newname == NULL)
COMPQUIET(bucket, 0);
COMPQUIET(hp, NULL);
COMPQUIET(newname_off, 0);
COMPQUIET(nlen, 0);
dbmp = NULL;
mfp = NULL;
nhp = NULL;
p = NULL;
locked = ret = 0;
if (!MPOOL_ON(env))
goto fsop;
dbmp = env->mp_handle;
mp = dbmp->reginfo[0].primary;
hp = R_ADDR(dbmp->reginfo, mp->ftab);
if (!op_is_remove) {
nlen = strlen(newname);
if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
NULL, nlen + 1, &newname_off, &p)) != 0)
return (ret);
memcpy(p, newname, nlen + 1);
}
if (inmem) {
DB_ASSERT(env, fullold != NULL);
hp += FNBUCKET(fullold, strlen(fullold));
if (!op_is_remove) {
bucket = FNBUCKET(newname, nlen);
nhp = R_ADDR(dbmp->reginfo, mp->ftab);
nhp += bucket;
}
} else
hp += FNBUCKET(fileid, DB_FILE_ID_LEN);
if (nhp != NULL && nhp < hp)
MUTEX_LOCK(env, nhp->mtx_hash);
MUTEX_LOCK(env, hp->mtx_hash);
if (nhp != NULL && nhp > hp)
MUTEX_LOCK(env, nhp->mtx_hash);
locked = 1;
if (!op_is_remove && inmem) {
SH_TAILQ_FOREACH(mfp, &nhp->hash_bucket, q, __mpoolfile)
if (!mfp->deadfile &&
mfp->no_backing_file && strcmp(newname,
R_ADDR(dbmp->reginfo, mfp->path_off)) == 0)
break;
if (mfp != NULL) {
ret = EEXIST;
goto err;
}
}
SH_TAILQ_FOREACH(mfp, &hp->hash_bucket, q, __mpoolfile) {
if (mfp->deadfile || F_ISSET(mfp, MP_TEMP))
continue;
if (memcmp(fileid, R_ADDR(
dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
continue;
break;
}
if (mfp == NULL) {
if (inmem) {
ret = ENOENT;
goto err;
}
goto fsop;
}
if (op_is_remove) {
MUTEX_LOCK(env, mfp->mutex);
if (mfp->no_backing_file)
mfp->mpf_cnt--;
mfp->deadfile = 1;
MUTEX_UNLOCK(env, mfp->mutex);
} else {
p = R_ADDR(dbmp->reginfo, mfp->path_off);
mfp->path_off = newname_off;
if (inmem && hp != nhp) {
DB_ASSERT(env, nhp != NULL);
SH_TAILQ_REMOVE(&hp->hash_bucket, mfp, q, __mpoolfile);
mfp->bucket = bucket;
SH_TAILQ_INSERT_TAIL(&nhp->hash_bucket, mfp, q);
}
}
fsop:
if (mfp == NULL || !mfp->no_backing_file) {
if (op_is_remove) {
if ((ret = __os_unlink(env, fullold, 0)) == ENOENT)
ret = 0;
} else {
DB_ASSERT(env, fullnew != NULL);
if (fullnew == NULL) {
ret = EINVAL;
goto err;
}
ret = __os_rename(env, fullold, fullnew, 1);
}
}
err: if (p != NULL)
__memp_free(&dbmp->reginfo[0], NULL, p);
if (locked == 1) {
MUTEX_UNLOCK(env, hp->mtx_hash);
if (nhp != NULL && nhp != hp)
MUTEX_UNLOCK(env, nhp->mtx_hash);
}
return (ret);
}
int
__memp_ftruncate(dbmfp, ip, pgno, flags)
DB_MPOOLFILE *dbmfp;
DB_THREAD_INFO *ip;
db_pgno_t pgno;
u_int32_t flags;
{
ENV *env;
MPOOLFILE *mfp;
void *pagep;
db_pgno_t last_pgno, pg;
int ret;
env = dbmfp->env;
mfp = dbmfp->mfp;
MUTEX_LOCK(env, mfp->mutex);
last_pgno = mfp->last_pgno;
MUTEX_UNLOCK(env, mfp->mutex);
if (pgno > last_pgno) {
if (LF_ISSET(MP_TRUNC_RECOVER))
return (0);
__db_errx(env, "Truncate beyond the end of file");
return (EINVAL);
}
pg = pgno;
do {
if ((ret = __memp_fget(dbmfp, &pg,
ip, NULL, DB_MPOOL_FREE, &pagep)) != 0)
return (ret);
} while (pg++ < last_pgno);
MUTEX_LOCK(env, mfp->mutex);
if (!F_ISSET(mfp, MP_TEMP) &&
!mfp->no_backing_file && pgno <= mfp->last_flushed_pgno)
#ifdef HAVE_FTRUNCATE
ret = __os_truncate(env,
dbmfp->fhp, pgno, mfp->stat.st_pagesize);
#else
ret = __db_zero_extend(env,
dbmfp->fhp, pgno, mfp->last_pgno, mfp->stat.st_pagesize);
#endif
if (ret == 0) {
mfp->last_pgno = pgno - 1;
if (mfp->last_flushed_pgno > mfp->last_pgno)
mfp->last_flushed_pgno = mfp->last_pgno;
}
MUTEX_UNLOCK(env, mfp->mutex);
return (ret);
}
#ifdef HAVE_FTRUNCATE
int
__memp_alloc_freelist(dbmfp, nelems, listp)
DB_MPOOLFILE *dbmfp;
u_int32_t nelems;
db_pgno_t **listp;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOLFILE *mfp;
void *retp;
int ret;
env = dbmfp->env;
dbmp = env->mp_handle;
mfp = dbmfp->mfp;
*listp = NULL;
mfp->free_ref++;
if (mfp->free_size != 0)
return (EBUSY);
mfp->free_cnt = nelems;
if (nelems == 0)
nelems = 50;
if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
NULL, nelems * sizeof(db_pgno_t), &mfp->free_list, &retp)) != 0)
return (ret);
mfp->free_size = nelems * sizeof(db_pgno_t);
*listp = retp;
return (0);
}
int
__memp_free_freelist(dbmfp)
DB_MPOOLFILE *dbmfp;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOLFILE *mfp;
env = dbmfp->env;
dbmp = env->mp_handle;
mfp = dbmfp->mfp;
DB_ASSERT(env, mfp->free_ref > 0);
if (--mfp->free_ref > 0)
return (0);
DB_ASSERT(env, mfp->free_size != 0);
MPOOL_SYSTEM_LOCK(env);
__memp_free(dbmp->reginfo, NULL, R_ADDR(dbmp->reginfo, mfp->free_list));
MPOOL_SYSTEM_UNLOCK(env);
mfp->free_cnt = 0;
mfp->free_list = 0;
mfp->free_size = 0;
return (0);
}
int
__memp_get_freelist(dbmfp, nelemp, listp)
DB_MPOOLFILE *dbmfp;
u_int32_t *nelemp;
db_pgno_t **listp;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOLFILE *mfp;
env = dbmfp->env;
dbmp = env->mp_handle;
mfp = dbmfp->mfp;
if (mfp->free_size == 0) {
*nelemp = 0;
*listp = NULL;
} else {
*nelemp = mfp->free_cnt;
*listp = R_ADDR(dbmp->reginfo, mfp->free_list);
}
return (0);
}
int
__memp_extend_freelist(dbmfp, count, listp)
DB_MPOOLFILE *dbmfp;
u_int32_t count;
db_pgno_t **listp;
{
DB_MPOOL *dbmp;
ENV *env;
MPOOLFILE *mfp;
int ret;
void *retp;
env = dbmfp->env;
dbmp = env->mp_handle;
mfp = dbmfp->mfp;
if (mfp->free_size == 0)
return (EINVAL);
if (count * sizeof(db_pgno_t) > mfp->free_size) {
mfp->free_size =
(size_t)DB_ALIGN(count * sizeof(db_pgno_t), 512);
*listp = R_ADDR(dbmp->reginfo, mfp->free_list);
if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
NULL, mfp->free_size, &mfp->free_list, &retp)) != 0)
return (ret);
memcpy(retp, *listp, mfp->free_cnt * sizeof(db_pgno_t));
MPOOL_SYSTEM_LOCK(env);
__memp_free(dbmp->reginfo, NULL, *listp);
MPOOL_SYSTEM_UNLOCK(env);
}
mfp->free_cnt = count;
*listp = R_ADDR(dbmp->reginfo, mfp->free_list);
return (0);
}
#endif
void
__memp_set_last_pgno(dbmfp, pgno)
DB_MPOOLFILE *dbmfp;
db_pgno_t pgno;
{
dbmfp->mfp->last_pgno = pgno;
}