#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: dbreg_util.c,v 1.2 2004/03/30 01:21:33 jtownsen Exp $";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
#include "dbinc/log.h"
#include "dbinc/txn.h"
static int __dbreg_check_master __P((DB_ENV *, u_int8_t *, char *));
int
__dbreg_add_dbentry(dbenv, dblp, dbp, ndx)
DB_ENV *dbenv;
DB_LOG *dblp;
DB *dbp;
int32_t ndx;
{
int32_t i;
int ret;
ret = 0;
MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
if (dblp->dbentry_cnt <= ndx) {
if ((ret = __os_realloc(dbenv,
(ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY),
&dblp->dbentry)) != 0)
goto err;
for (i = dblp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
dblp->dbentry[i].dbp = NULL;
dblp->dbentry[i].deleted = 0;
}
dblp->dbentry_cnt = i;
}
DB_ASSERT(dblp->dbentry[ndx].dbp == NULL);
dblp->dbentry[ndx].deleted = dbp == NULL;
dblp->dbentry[ndx].dbp = dbp;
err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
return (ret);
}
void
__dbreg_rem_dbentry(dblp, ndx)
DB_LOG *dblp;
int32_t ndx;
{
MUTEX_THREAD_LOCK(dblp->dbenv, dblp->mutexp);
if (dblp->dbentry_cnt > ndx) {
dblp->dbentry[ndx].dbp = NULL;
dblp->dbentry[ndx].deleted = 0;
}
MUTEX_THREAD_UNLOCK(dblp->dbenv, dblp->mutexp);
}
int
__dbreg_open_files(dbenv)
DB_ENV *dbenv;
{
DB_LOG *dblp;
DB_LSN r_unused;
DBT *dbtp, fid_dbt, t;
FNAME *fnp;
LOG *lp;
int ret;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
ret = 0;
MUTEX_LOCK(dbenv, &lp->fq_mutex);
for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
if (fnp->name_off == INVALID_ROFF)
dbtp = NULL;
else {
memset(&t, 0, sizeof(t));
t.data = R_ADDR(&dblp->reginfo, fnp->name_off);
t.size = (u_int32_t)strlen(t.data) + 1;
dbtp = &t;
}
memset(&fid_dbt, 0, sizeof(fid_dbt));
fid_dbt.data = fnp->ufid;
fid_dbt.size = DB_FILE_ID_LEN;
if ((ret = __dbreg_register_log(dbenv,
NULL, &r_unused,
fnp->is_durable ? 0 : DB_LOG_NOT_DURABLE,
F_ISSET(dblp, DBLOG_RECOVER) ? DBREG_RCLOSE : DBREG_CHKPNT,
dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno,
TXN_INVALID)) != 0)
break;
}
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
return (ret);
}
int
__dbreg_close_files(dbenv)
DB_ENV *dbenv;
{
DB_LOG *dblp;
DB *dbp;
int ret, t_ret;
int32_t i;
if (!LOGGING_ON(dbenv))
return (0);
dblp = dbenv->lg_handle;
ret = 0;
MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
for (i = 0; i < dblp->dbentry_cnt; i++) {
if ((dbp = dblp->dbentry[i].dbp) != NULL) {
MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
if (F_ISSET(dbp, DB_AM_RECOVER))
t_ret = __db_close(dbp,
NULL, dbp->mpf == NULL ? DB_NOSYNC : 0);
else
t_ret = __dbreg_revoke_id(
dbp, 0, DB_LOGFILEID_INVALID);
if (ret == 0)
ret = t_ret;
MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
}
dblp->dbentry[i].deleted = 0;
dblp->dbentry[i].dbp = NULL;
}
MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
return (ret);
}
int
__dbreg_id_to_db(dbenv, txn, dbpp, ndx, inc)
DB_ENV *dbenv;
DB_TXN *txn;
DB **dbpp;
int32_t ndx;
int inc;
{
return (__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, 1));
}
int
__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen)
DB_ENV *dbenv;
DB_TXN *txn;
DB **dbpp;
int32_t ndx;
int inc, tryopen;
{
DB_LOG *dblp;
FNAME *fname;
int ret;
char *name;
ret = 0;
dblp = dbenv->lg_handle;
COMPQUIET(inc, 0);
MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
if (ndx >= dblp->dbentry_cnt ||
(!dblp->dbentry[ndx].deleted && dblp->dbentry[ndx].dbp == NULL)) {
if (!tryopen || F_ISSET(dblp, DBLOG_RECOVER)) {
ret = ENOENT;
goto err;
}
MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0)
return (ENOENT);
name = R_ADDR(&dblp->reginfo, fname->name_off);
if ((ret = __dbreg_do_open(dbenv, txn, dblp,
fname->ufid, name, fname->s_type,
ndx, fname->meta_pgno, NULL, 0)) != 0)
return (ret);
*dbpp = dblp->dbentry[ndx].dbp;
return (0);
}
if (dblp->dbentry[ndx].deleted) {
ret = DB_DELETED;
goto err;
}
if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL)
ret = ENOENT;
err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
return (ret);
}
int
__dbreg_id_to_fname(dblp, lid, have_lock, fnamep)
DB_LOG *dblp;
int32_t lid;
int have_lock;
FNAME **fnamep;
{
DB_ENV *dbenv;
FNAME *fnp;
LOG *lp;
int ret;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
ret = -1;
if (!have_lock)
MUTEX_LOCK(dbenv, &lp->fq_mutex);
for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
if (fnp->id == lid) {
*fnamep = fnp;
ret = 0;
break;
}
}
if (!have_lock)
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
return (ret);
}
int
__dbreg_fid_to_fname(dblp, fid, have_lock, fnamep)
DB_LOG *dblp;
u_int8_t *fid;
int have_lock;
FNAME **fnamep;
{
DB_ENV *dbenv;
FNAME *fnp;
LOG *lp;
int ret;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
ret = -1;
if (!have_lock)
MUTEX_LOCK(dbenv, &lp->fq_mutex);
for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) {
*fnamep = fnp;
ret = 0;
break;
}
}
if (!have_lock)
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
return (ret);
}
int
__dbreg_get_name(dbenv, fid, namep)
DB_ENV *dbenv;
u_int8_t *fid;
char **namep;
{
DB_LOG *dblp;
FNAME *fname;
dblp = dbenv->lg_handle;
if (dblp != NULL && __dbreg_fid_to_fname(dblp, fid, 0, &fname) == 0) {
*namep = R_ADDR(&dblp->reginfo, fname->name_off);
return (0);
}
return (-1);
}
int
__dbreg_do_open(dbenv,
txn, lp, uid, name, ftype, ndx, meta_pgno, info, id)
DB_ENV *dbenv;
DB_TXN *txn;
DB_LOG *lp;
u_int8_t *uid;
char *name;
DBTYPE ftype;
int32_t ndx;
db_pgno_t meta_pgno;
void *info;
u_int32_t id;
{
DB *dbp;
int ret;
u_int32_t cstat;
if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0)
return (ret);
F_SET(dbp, DB_AM_RECOVER);
if (meta_pgno != PGNO_BASE_MD) {
memcpy(dbp->fileid, uid, DB_FILE_ID_LEN);
dbp->meta_pgno = meta_pgno;
}
if ((ret = __db_open(dbp, txn, name, NULL,
ftype, DB_ODDFILESIZE, __db_omode("rw----"), meta_pgno)) == 0) {
if ((meta_pgno != PGNO_BASE_MD &&
__dbreg_check_master(dbenv, uid, name) != 0) ||
memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
cstat = TXN_IGNORE;
else
cstat = TXN_EXPECTED;
if ((ret = __dbreg_assign_id(dbp, ndx)) != 0)
goto err;
if (id != TXN_INVALID) {
if ((ret = __db_txnlist_update(dbenv,
info, id, cstat, NULL)) == TXN_NOTFOUND)
ret = __db_txnlist_add(dbenv,
info, id, cstat, NULL);
else if (ret > 0)
ret = 0;
}
err: if (cstat == TXN_IGNORE)
goto not_right;
return (ret);
} else if (ret == ENOENT) {
if (id != TXN_INVALID && (ret = __db_txnlist_update(dbenv,
info, id, TXN_UNEXPECTED, NULL)) == TXN_NOTFOUND)
ret = __db_txnlist_add(dbenv,
info, id, TXN_UNEXPECTED, NULL);
}
not_right:
(void)__db_close(dbp, NULL, 0);
(void)__dbreg_add_dbentry(dbenv, lp, NULL, ndx);
return (ret);
}
static int
__dbreg_check_master(dbenv, uid, name)
DB_ENV *dbenv;
u_int8_t *uid;
char *name;
{
DB *dbp;
int ret;
ret = 0;
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return (ret);
F_SET(dbp, DB_AM_RECOVER);
ret = __db_open(dbp,
NULL, name, NULL, DB_BTREE, 0, __db_omode("rw----"), PGNO_BASE_MD);
if (ret == 0 && memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
ret = EINVAL;
(void)__db_close(dbp, NULL, 0);
return (ret);
}
int
__dbreg_lazy_id(dbp)
DB *dbp;
{
DB_ENV *dbenv;
DB_LOG *dblp;
DB_TXN *txn;
FNAME *fnp;
LOG *lp;
int32_t id;
int ret;
dbenv = dbp->dbenv;
DB_ASSERT(IS_REP_MASTER(dbenv));
dbenv = dbp->dbenv;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
fnp = dbp->log_filename;
MUTEX_LOCK(dbenv, &lp->fq_mutex);
if (fnp->id != DB_LOGFILEID_INVALID) {
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
return (0);
}
id = DB_LOGFILEID_INVALID;
if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
goto err;
if ((ret = __dbreg_get_id(dbp, txn, &id)) != 0) {
(void)__txn_abort(txn);
goto err;
}
if ((ret = __txn_commit(txn, DB_TXN_NOSYNC)) != 0)
goto err;
fnp->id = id;
err:
if (ret != 0 && id != DB_LOGFILEID_INVALID)
(void)__dbreg_revoke_id(dbp, 1, id);
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
return (ret);
}
int
__dbreg_push_id(dbenv, id)
DB_ENV *dbenv;
int32_t id;
{
DB_LOG *dblp;
LOG *lp;
int32_t *stack, *newstack;
int ret;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
if (lp->free_fid_stack != INVALID_ROFF)
stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
else
stack = NULL;
if (lp->free_fids_alloced <= lp->free_fids + 1) {
R_LOCK(dbenv, &dblp->reginfo);
if ((ret = __db_shalloc(dblp->reginfo.addr,
(lp->free_fids_alloced + 20) * sizeof(u_int32_t), 0,
&newstack)) != 0) {
R_UNLOCK(dbenv, &dblp->reginfo);
return (ret);
}
memcpy(newstack, stack,
lp->free_fids_alloced * sizeof(u_int32_t));
lp->free_fid_stack = R_OFFSET(&dblp->reginfo, newstack);
lp->free_fids_alloced += 20;
if (stack != NULL)
__db_shalloc_free(dblp->reginfo.addr, stack);
stack = newstack;
R_UNLOCK(dbenv, &dblp->reginfo);
}
DB_ASSERT(stack != NULL);
stack[lp->free_fids++] = id;
return (0);
}
int
__dbreg_pop_id(dbenv, id)
DB_ENV *dbenv;
int32_t *id;
{
DB_LOG *dblp;
LOG *lp;
int32_t *stack;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
if (lp->free_fid_stack != INVALID_ROFF && lp->free_fids > 0) {
stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
*id = stack[--lp->free_fids];
} else
*id = DB_LOGFILEID_INVALID;
return (0);
}
int
__dbreg_pluck_id(dbenv, id)
DB_ENV *dbenv;
int32_t id;
{
DB_LOG *dblp;
LOG *lp;
int32_t *stack;
int i;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
if (lp->free_fid_stack != INVALID_ROFF) {
stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
for (i = 0; i < lp->free_fids; i++)
if (id == stack[i]) {
stack[i] = stack[lp->free_fids - 1];
lp->free_fids--;
return (0);
}
}
return (0);
}
#ifdef DEBUG
void
__dbreg_print_dblist(dbenv)
DB_ENV *dbenv;
{
DB *dbp;
DB_LOG *dblp;
FNAME *fnp;
LOG *lp;
int del, first;
char *name;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
MUTEX_LOCK(dbenv, &lp->fq_mutex);
for (first = 1, fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
if (first) {
first = 0;
__db_err(dbenv,
"ID\t\t\tName\tType\tPgno\tTxnid\tDBP-info");
}
if (fnp->name_off == INVALID_ROFF)
name = "";
else
name = R_ADDR(&dblp->reginfo, fnp->name_off);
dbp = fnp->id >= dblp->dbentry_cnt ? NULL :
dblp->dbentry[fnp->id].dbp;
del = fnp->id >= dblp->dbentry_cnt ? 0 :
dblp->dbentry[fnp->id].deleted;
__db_err(dbenv, "%ld\t%s\t\t\t%s\t%lu\t%lx\t%s %d %lx %lx",
(long)fnp->id, name,
__db_dbtype_to_string(fnp->s_type),
(u_long)fnp->meta_pgno, (u_long)fnp->create_txnid,
dbp == NULL ? "No DBP" : "DBP", del, P_TO_ULONG(dbp),
(u_long)(dbp == NULL ? 0 : dbp->flags));
}
MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
}
#endif