You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
8.9 KiB
334 lines
8.9 KiB
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1996, 1997, 1998, 1999
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
#include "db_config.h"
|
|
|
|
#ifndef lint
|
|
static const char sccsid[] = "@(#)mp_region.c 11.4 (Sleepycat) 10/19/99";
|
|
#endif /* not lint */
|
|
|
|
#ifndef NO_SYSTEM_INCLUDES
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "db_int.h"
|
|
#include "db_shash.h"
|
|
#include "mp.h"
|
|
|
|
static int CDB___mcache_init __P((DB_ENV *, DB_MPOOL *, int, int));
|
|
static int CDB___mpool_init __P((DB_ENV *, DB_MPOOL *, int));
|
|
|
|
/*
|
|
* CDB___memp_open --
|
|
* Internal version of memp_open: only called from DB_ENV->open.
|
|
*
|
|
* PUBLIC: int CDB___memp_open __P((DB_ENV *));
|
|
*/
|
|
int
|
|
CDB___memp_open(dbenv)
|
|
DB_ENV *dbenv;
|
|
{
|
|
DB_MPOOL *dbmp;
|
|
MPOOL *mp;
|
|
roff_t mpr_size, reg_size, *regids;
|
|
int i, htab_buckets, ret;
|
|
|
|
/* Figure out how big each cache region is. */
|
|
reg_size = dbenv->mp_gbytes / dbenv->mp_ncache;
|
|
reg_size += (dbenv->mp_gbytes % dbenv->mp_ncache) / dbenv->mp_ncache;
|
|
reg_size += dbenv->mp_bytes / dbenv->mp_ncache;
|
|
|
|
/*
|
|
* Figure out how many hash buckets each region will have. Assume we
|
|
* want to keep the hash chains with under 10 pages on each chain. We
|
|
* don't know the pagesize in advance, and it may differ for different
|
|
* files. Use a pagesize of 1K for the calculation -- we walk these
|
|
* chains a lot, they must be kept short.
|
|
*/
|
|
htab_buckets = CDB___db_tablesize((reg_size / (1 * 1024)) / 10);
|
|
|
|
/* Create and initialize the DB_MPOOL structure. */
|
|
if ((ret = CDB___os_calloc(1, sizeof(*dbmp), &dbmp)) != 0)
|
|
return (ret);
|
|
LIST_INIT(&dbmp->dbregq);
|
|
TAILQ_INIT(&dbmp->dbmfq);
|
|
dbmp->dbenv = dbenv;
|
|
|
|
/* Clear locking for avoiding mp_alloc recursion */
|
|
dbmp->recursion_level = 0;
|
|
|
|
/*
|
|
* Join/create the mpool region. If this is a local region we don't
|
|
* need much space because the most we'll store there is the pair of
|
|
* MPOOL and MPOOLFILE structures. If we're creating a full-blown
|
|
* database environment, be generous -- I'd rather not fail because
|
|
* we ran out of space.
|
|
*/
|
|
dbmp->reginfo.id = REG_ID_MPOOL;
|
|
dbmp->reginfo.mode = dbenv->db_mode;
|
|
if (F_ISSET(dbenv, DB_ENV_DBLOCAL))
|
|
mpr_size = sizeof(MPOOL) + sizeof(MPOOLFILE) + 5 * 1024;
|
|
else
|
|
mpr_size = sizeof(MPOOL) +
|
|
DB_MPOOLFILE_DEF * sizeof(MPOOLFILE) + 10 * 1024;
|
|
if (F_ISSET(dbenv, DB_ENV_CREATE))
|
|
F_SET(&dbmp->reginfo, REGION_CREATE_OK);
|
|
if ((ret = CDB___db_r_attach(dbenv, &dbmp->reginfo, mpr_size)) != 0)
|
|
goto err;
|
|
|
|
/*
|
|
* If we created the region, initialize it and any additional regions,
|
|
* otherwise join any additional regions.
|
|
*/
|
|
if (F_ISSET(&dbmp->reginfo, REGION_CREATE)) {
|
|
/* Initialize the primary region. */
|
|
if ((ret = CDB___mpool_init(dbenv, dbmp, dbenv->mp_ncache)) != 0)
|
|
goto err;
|
|
|
|
/*
|
|
* We know how many regions there are going to be, allocate
|
|
* the REGINFO structures and fill in local copies of that
|
|
* information.
|
|
*/
|
|
if ((ret = CDB___os_calloc(
|
|
dbenv->mp_ncache, sizeof(REGINFO), &dbmp->c_reginfo)) != 0)
|
|
goto err;
|
|
dbmp->nc_reg = dbenv->mp_ncache;
|
|
|
|
/* Make sure we don't clear the wrong entries on error. */
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
dbmp->c_reginfo[i].id = REG_ID_INVALID;
|
|
|
|
/*
|
|
* Create/initialize the cache regions and copy their IDs
|
|
* into the primary region.
|
|
*/
|
|
mp = R_ADDR(&dbmp->reginfo, dbmp->reginfo.rp->primary);
|
|
regids = R_ADDR(&dbmp->reginfo, mp->c_regids);
|
|
for (i = 0; i < dbmp->nc_reg; ++i) {
|
|
dbmp->c_reginfo[i].id = REG_ID_INVALID;
|
|
dbmp->c_reginfo[i].mode = dbenv->db_mode;
|
|
F_SET(&dbmp->c_reginfo[i], REGION_CREATE_OK);
|
|
if ((ret = CDB___db_r_attach(
|
|
dbenv, &dbmp->c_reginfo[i], reg_size)) != 0)
|
|
goto err;
|
|
if ((ret =
|
|
CDB___mcache_init(dbenv, dbmp, htab_buckets, i)) != 0)
|
|
goto err;
|
|
R_UNLOCK(dbenv, &dbmp->c_reginfo[i]);
|
|
|
|
regids[i] = dbmp->c_reginfo[i].id;
|
|
}
|
|
} else {
|
|
/*
|
|
* We know how many regions there are going to be, allocate
|
|
* the REGINFO structures and fill in local copies of that
|
|
* information.
|
|
*/
|
|
mp = R_ADDR(&dbmp->reginfo, dbmp->reginfo.rp->primary);
|
|
if ((ret = CDB___os_calloc(
|
|
mp->nc_reg, sizeof(REGINFO), &dbmp->c_reginfo)) != 0)
|
|
goto err;
|
|
dbmp->nc_reg = mp->nc_reg;
|
|
|
|
/* Make sure we don't clear the wrong entries on error. */
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
dbmp->c_reginfo[i].id = REG_ID_INVALID;
|
|
|
|
/* Join additional regions. */
|
|
regids = R_ADDR(&dbmp->reginfo, mp->c_regids);
|
|
for (i = 0; i < dbmp->nc_reg; ++i) {
|
|
dbmp->c_reginfo[i].id = regids[i];
|
|
dbmp->c_reginfo[i].mode = 0;
|
|
if ((ret =
|
|
CDB___db_r_attach(dbenv, &dbmp->c_reginfo[i], 0)) != 0)
|
|
goto err;
|
|
R_UNLOCK(dbenv, &dbmp->c_reginfo[i]);
|
|
}
|
|
}
|
|
|
|
/* Set the local addresses for the primary and cache regions. */
|
|
dbmp->reginfo.primary = mp =
|
|
R_ADDR(&dbmp->reginfo, dbmp->reginfo.rp->primary);
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
dbmp->c_reginfo[i].primary =
|
|
R_ADDR(&dbmp->c_reginfo[i], dbmp->c_reginfo[i].rp->primary);
|
|
|
|
R_UNLOCK(dbenv, &dbmp->reginfo);
|
|
|
|
/* If the region is threaded, allocate a mutex to lock the handles. */
|
|
if (F_ISSET(dbenv, DB_ENV_THREAD)) {
|
|
if ((ret = CDB___db_mutex_alloc(
|
|
dbenv, &dbmp->reginfo, &dbmp->mutexp)) != 0) {
|
|
goto err;
|
|
}
|
|
if ((ret =
|
|
__db_mutex_init(dbenv, dbmp->mutexp, 0, MUTEX_THREAD)) != 0)
|
|
goto err;
|
|
}
|
|
|
|
dbenv->mp_handle = dbmp;
|
|
return (0);
|
|
|
|
err: if (dbmp->reginfo.addr != NULL) {
|
|
if (F_ISSET(&dbmp->reginfo, REGION_CREATE))
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
if (dbmp->c_reginfo[i].id != REG_ID_INVALID)
|
|
F_SET(dbmp->c_reginfo[i].rp, REG_DEAD);
|
|
|
|
R_UNLOCK(dbenv, &dbmp->reginfo);
|
|
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
if (dbmp->c_reginfo[i].id != REG_ID_INVALID)
|
|
(void)CDB___db_r_detach(
|
|
dbenv, &dbmp->c_reginfo[i], 0);
|
|
CDB___os_free(dbmp->c_reginfo,
|
|
dbmp->nc_reg * sizeof(*dbmp->c_reginfo));
|
|
}
|
|
CDB___os_free(dbmp, sizeof(*dbmp));
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* CDB___mpool_init --
|
|
* Initialize a MPOOL structure in shared memory.
|
|
*/
|
|
static int
|
|
CDB___mpool_init(dbenv, dbmp, nc_reg)
|
|
DB_ENV *dbenv;
|
|
DB_MPOOL *dbmp;
|
|
int nc_reg;
|
|
{
|
|
MPOOL *mp;
|
|
int ret;
|
|
void *p;
|
|
|
|
if ((ret = CDB___db_shalloc(dbmp->reginfo.addr,
|
|
sizeof(*mp), 0, &dbmp->reginfo.primary)) != 0)
|
|
return (ret);
|
|
dbmp->reginfo.rp->primary =
|
|
R_OFFSET(&dbmp->reginfo, dbmp->reginfo.primary);
|
|
mp = dbmp->reginfo.primary;
|
|
memset(mp, 0, sizeof(*mp));
|
|
|
|
SH_TAILQ_INIT(&mp->mpfq);
|
|
if ((ret = __db_mutex_init(dbenv, &mp->sync_mutex,
|
|
R_OFFSET(&dbmp->reginfo, &mp->sync_mutex) + DB_FCNTL_OFF_MPOOL,
|
|
0)) != 0)
|
|
return (ret);
|
|
|
|
ZERO_LSN(mp->lsn);
|
|
mp->lsn_cnt = 0;
|
|
|
|
mp->nc_reg = nc_reg;
|
|
if ((ret = CDB___db_shalloc(
|
|
dbmp->reginfo.addr, nc_reg * sizeof(int), 0, &p)) != 0) {
|
|
CDB___db_shalloc_free(dbmp->reginfo.addr, dbmp->reginfo.primary);
|
|
return (ret);
|
|
}
|
|
mp->c_regids = R_OFFSET(&dbmp->reginfo, p);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* CDB___mcache_init --
|
|
* Initialize a MCACHE structure in shared memory.
|
|
*/
|
|
static int
|
|
CDB___mcache_init(dbenv, dbmp, htab_buckets, reginfo_off)
|
|
DB_ENV *dbenv;
|
|
DB_MPOOL *dbmp;
|
|
int htab_buckets, reginfo_off;
|
|
{
|
|
DB_HASHTAB *htab;
|
|
MCACHE *mc;
|
|
MPOOL *mp;
|
|
REGINFO *reginfo;
|
|
int ret;
|
|
|
|
COMPQUIET(dbenv, NULL);
|
|
|
|
mp = dbmp->reginfo.primary;
|
|
|
|
reginfo = &dbmp->c_reginfo[reginfo_off];
|
|
if ((ret = CDB___db_shalloc(reginfo->addr,
|
|
sizeof(*mc), 0, ®info->primary)) != 0)
|
|
return (ret);
|
|
reginfo->rp->primary = R_OFFSET(reginfo, reginfo->primary);
|
|
mc = reginfo->primary;
|
|
memset(mc, 0, sizeof(*mc));
|
|
|
|
SH_TAILQ_INIT(&mc->bhq);
|
|
|
|
/* Allocate hash table space and initialize it. */
|
|
if ((ret = CDB___db_shalloc(reginfo->addr,
|
|
htab_buckets * sizeof(DB_HASHTAB), 0, &htab)) != 0) {
|
|
CDB___db_shalloc_free(reginfo->addr, reginfo->primary);
|
|
return (ret);
|
|
}
|
|
CDB___db_hashinit(htab, htab_buckets);
|
|
mc->htab = R_OFFSET(reginfo, htab);
|
|
mc->htab_buckets = htab_buckets;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* CDB___memp_close --
|
|
* Internal version of memp_close: only called from DB_ENV->close.
|
|
*
|
|
* PUBLIC: int CDB___memp_close __P((DB_ENV *));
|
|
*/
|
|
int
|
|
CDB___memp_close(dbenv)
|
|
DB_ENV *dbenv;
|
|
{
|
|
DB_MPOOL *dbmp;
|
|
DB_MPOOLFILE *dbmfp;
|
|
DB_MPREG *mpreg;
|
|
int i, ret, t_ret;
|
|
|
|
ret = 0;
|
|
dbmp = dbenv->mp_handle;
|
|
|
|
/* Discard DB_MPREGs. */
|
|
while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
|
|
LIST_REMOVE(mpreg, q);
|
|
CDB___os_free(mpreg, sizeof(DB_MPREG));
|
|
}
|
|
|
|
/* Discard DB_MPOOLFILEs. */
|
|
while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL) {
|
|
if(F_ISSET(dbmfp, MP_CMPR)) {
|
|
dbmfp->cmpr_context.weakcmpr = 0;
|
|
F_CLR(dbmfp, MP_CMPR);
|
|
}
|
|
if ((t_ret = CDB_memp_fclose(dbmfp)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
}
|
|
|
|
/* Discard the thread mutex. */
|
|
if (dbmp->mutexp != NULL)
|
|
CDB___db_mutex_free(dbenv, &dbmp->reginfo, dbmp->mutexp);
|
|
|
|
/* Detach from the region(s). */
|
|
for (i = 0; i < dbmp->nc_reg; ++i)
|
|
if ((t_ret = CDB___db_r_detach(
|
|
dbenv, &dbmp->c_reginfo[i], 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
if ((t_ret = CDB___db_r_detach(dbenv, &dbmp->reginfo, 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
CDB___os_free(dbmp->c_reginfo, dbmp->nc_reg * sizeof(*dbmp->c_reginfo));
|
|
CDB___os_free(dbmp, sizeof(*dbmp));
|
|
|
|
return (ret);
|
|
}
|