#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
#include "dbinc/fop.h"
#include "dbinc/mp.h"
#include "dbinc/txn.h"
static int __dbreg_check_master __P((ENV *, u_int8_t *, char *));
int
__dbreg_add_dbentry(env, dblp, dbp, ndx)
ENV *env;
DB_LOG *dblp;
DB *dbp;
int32_t ndx;
{
int32_t i;
int ret;
ret = 0;
MUTEX_LOCK(env, dblp->mtx_dbreg);
if (dblp->dbentry_cnt <= ndx) {
if ((ret = __os_realloc(env,
(size_t)(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(env, dblp->dbentry[ndx].dbp == NULL);
dblp->dbentry[ndx].deleted = dbp == NULL;
dblp->dbentry[ndx].dbp = dbp;
err: MUTEX_UNLOCK(env, dblp->mtx_dbreg);
return (ret);
}
int
__dbreg_rem_dbentry(dblp, ndx)
DB_LOG *dblp;
int32_t ndx;
{
MUTEX_LOCK(dblp->env, dblp->mtx_dbreg);
if (dblp->dbentry_cnt > ndx) {
dblp->dbentry[ndx].dbp = NULL;
dblp->dbentry[ndx].deleted = 0;
}
MUTEX_UNLOCK(dblp->env, dblp->mtx_dbreg);
return (0);
}
int
__dbreg_log_files(env, opcode)
ENV *env;
u_int32_t opcode;
{
DBT *dbtp, fid_dbt, t;
DB_LOG *dblp;
DB_LSN r_unused;
FNAME *fnp;
LOG *lp;
u_int32_t lopcode;
int ret;
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
ret = 0;
MUTEX_LOCK(env, lp->mtx_filelist);
SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) {
if (fnp->id == DB_LOGFILEID_INVALID)
continue;
if (fnp->fname_off == INVALID_ROFF)
dbtp = NULL;
else {
memset(&t, 0, sizeof(t));
t.data = R_ADDR(&dblp->reginfo, fnp->fname_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;
lopcode = opcode;
if ( opcode == DBREG_CHKPNT && F_ISSET(fnp, DBREG_EXCL))
lopcode = DBREG_XCHKPNT;
if ((ret = __dbreg_register_log(env, NULL, &r_unused,
F_ISSET(fnp, DB_FNAME_DURABLE) ? 0 : DB_LOG_NOT_DURABLE,
lopcode | F_ISSET(fnp, DB_FNAME_DBREG_MASK),
dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno,
TXN_INVALID)) != 0)
break;
}
MUTEX_UNLOCK(env, lp->mtx_filelist);
return (ret);
}
int
__dbreg_log_nofiles(env)
ENV *env;
{
DB_LOG *dblp;
LOG *lp;
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
return (SH_TAILQ_EMPTY(&lp->fq));
}
int
__dbreg_close_files(env, do_restored)
ENV *env;
int do_restored;
{
DB *dbp;
DB_LOG *dblp;
int ret, t_ret;
int32_t i;
if (!LOGGING_ON(env))
return (0);
dblp = env->lg_handle;
ret = 0;
MUTEX_LOCK(env, dblp->mtx_dbreg);
for (i = 0; i < dblp->dbentry_cnt; i++) {
if ((dbp = dblp->dbentry[i].dbp) != NULL) {
if (do_restored &&
!F_ISSET(dbp->log_filename, DB_FNAME_RESTORED))
continue;
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
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_LOCK(env, dblp->mtx_dbreg);
}
dblp->dbentry[i].deleted = 0;
dblp->dbentry[i].dbp = NULL;
}
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
return (ret);
}
int
__dbreg_close_file(env, fnp)
ENV *env;
FNAME *fnp;
{
DB *dbp;
DB_LOG *dblp;
dblp = env->lg_handle;
dbp = dblp->dbentry[fnp->id].dbp;
if (dbp == NULL)
return (0);
DB_ASSERT(env, dbp->log_filename == fnp);
DB_ASSERT(env, F_ISSET(dbp, DB_AM_RECOVER));
return (__db_close(dbp, NULL, DB_NOSYNC));
}
int
__dbreg_mark_restored(env)
ENV *env;
{
DB_LOG *dblp;
FNAME *fnp;
LOG *lp;
if (!LOGGING_ON(env))
return (0);
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
MUTEX_LOCK(env, lp->mtx_filelist);
SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname)
if (fnp->id != DB_LOGFILEID_INVALID)
F_SET(fnp, DB_FNAME_RESTORED);
MUTEX_UNLOCK(env, lp->mtx_filelist);
return (0);
}
int
__dbreg_invalidate_files(env, do_restored)
ENV *env;
int do_restored;
{
DB_LOG *dblp;
FNAME *fnp;
LOG *lp;
int ret;
if (!LOGGING_ON(env))
return (0);
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
ret = 0;
MUTEX_LOCK(env, lp->mtx_filelist);
SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) {
if (F_ISSET(fnp, DB_FNAME_RESTORED) && !do_restored)
continue;
if (!F_ISSET(fnp, DB_FNAME_RESTORED) && do_restored)
continue;
if (fnp->id != DB_LOGFILEID_INVALID) {
if ((ret = __dbreg_log_close(env,
fnp, NULL, DBREG_RCLOSE)) != 0)
goto err;
fnp->old_id = fnp->id;
fnp->id = DB_LOGFILEID_INVALID;
}
}
err: MUTEX_UNLOCK(env, lp->mtx_filelist);
return (ret);
}
int
__dbreg_id_to_db(env, txn, dbpp, ndx, tryopen)
ENV *env;
DB_TXN *txn;
DB **dbpp;
int32_t ndx;
int tryopen;
{
DB_LOG *dblp;
FNAME *fname;
int ret;
char *name;
dblp = env->lg_handle;
ret = 0;
MUTEX_LOCK(env, dblp->mtx_dbreg);
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_UNLOCK(env, dblp->mtx_dbreg);
if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0)
return (ENOENT);
name = fname->fname_off == INVALID_ROFF ?
NULL : R_ADDR(&dblp->reginfo, fname->fname_off);
if ((ret = __dbreg_do_open(env, txn, dblp,
fname->ufid, name, fname->s_type, ndx, fname->meta_pgno,
NULL, TXN_INVALID, F_ISSET(fname, DB_FNAME_INMEM) ?
DBREG_REOPEN : DBREG_OPEN)) != 0)
return (ret);
*dbpp = dblp->dbentry[ndx].dbp;
return (*dbpp == NULL ? DB_DELETED : 0);
}
if (dblp->dbentry[ndx].deleted) {
ret = DB_DELETED;
goto err;
}
if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL)
ret = ENOENT;
else
if ((*dbpp)->mpf != NULL && (*dbpp)->mpf->mfp != NULL)
(*dbpp)->mpf->mfp->file_written = 1;
err: MUTEX_UNLOCK(env, dblp->mtx_dbreg);
return (ret);
}
int
__dbreg_id_to_fname(dblp, id, have_lock, fnamep)
DB_LOG *dblp;
int32_t id;
int have_lock;
FNAME **fnamep;
{
ENV *env;
FNAME *fnp;
LOG *lp;
int ret;
env = dblp->env;
lp = dblp->reginfo.primary;
ret = -1;
if (!have_lock)
MUTEX_LOCK(env, lp->mtx_filelist);
SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname)
if (fnp->id == id) {
*fnamep = fnp;
ret = 0;
break;
}
if (!have_lock)
MUTEX_UNLOCK(env, lp->mtx_filelist);
return (ret);
}
int
__dbreg_fid_to_fname(dblp, fid, have_lock, fnamep)
DB_LOG *dblp;
u_int8_t *fid;
int have_lock;
FNAME **fnamep;
{
ENV *env;
FNAME *fnp;
LOG *lp;
int ret;
env = dblp->env;
lp = dblp->reginfo.primary;
ret = -1;
if (!have_lock)
MUTEX_LOCK(env, lp->mtx_filelist);
SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname)
if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) {
*fnamep = fnp;
ret = 0;
break;
}
if (!have_lock)
MUTEX_UNLOCK(env, lp->mtx_filelist);
return (ret);
}
int
__dbreg_get_name(env, fid, fnamep, dnamep)
ENV *env;
u_int8_t *fid;
char **fnamep, **dnamep;
{
DB_LOG *dblp;
FNAME *fnp;
dblp = env->lg_handle;
if (dblp != NULL && __dbreg_fid_to_fname(dblp, fid, 0, &fnp) == 0) {
*fnamep = fnp->fname_off == INVALID_ROFF ?
NULL : R_ADDR(&dblp->reginfo, fnp->fname_off);
*dnamep = fnp->dname_off == INVALID_ROFF ?
NULL : R_ADDR(&dblp->reginfo, fnp->dname_off);
return (0);
}
*fnamep = *dnamep = NULL;
return (-1);
}
int
__dbreg_do_open(env,
txn, lp, uid, name, ftype, ndx, meta_pgno, info, id, opcode)
ENV *env;
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, opcode;
{
DB *dbp;
u_int32_t cstat, ret_stat;
int ret, t_ret, try_inmem;
char *dname, *fname;
cstat = TXN_EXPECTED;
fname = name;
dname = NULL;
try_inmem = 0;
retry_inmem:
if ((ret = __db_create_internal(&dbp, lp->env, 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 (opcode == DBREG_PREOPEN) {
dbp->type = ftype;
if ((ret = __dbreg_setup(dbp, name, NULL, id)) != 0)
goto err;
MAKE_INMEM(dbp);
goto skip_open;
}
if (opcode == DBREG_REOPEN || opcode == DBREG_XREOPEN || try_inmem) {
MAKE_INMEM(dbp);
fname = NULL;
dname = name;
}
if (opcode == DBREG_XOPEN || opcode == DBREG_XCHKPNT ||
opcode == DBREG_XREOPEN)
F2_SET(dbp, DB2_AM_EXCL|DB2_AM_INTEXCL);
if ((ret = __db_open(dbp, NULL, txn, fname, dname, ftype,
DB_DURABLE_UNKNOWN | DB_ODDFILESIZE,
DB_MODE_600, meta_pgno)) == 0) {
skip_open:
if ((meta_pgno != PGNO_BASE_MD &&
__dbreg_check_master(env, uid, name) != 0) ||
memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
cstat = TXN_UNEXPECTED;
else
cstat = TXN_EXPECTED;
if ((ret = __dbreg_assign_id(dbp, ndx, 0)) != 0)
goto err;
if (txn != NULL && (ret =
__txn_record_fname(env, txn, dbp->log_filename)) != 0)
goto err;
--dbp->log_filename->txn_ref;
if (id != TXN_INVALID)
ret = __db_txnlist_update(env,
info, id, cstat, NULL, &ret_stat, 1);
err: if (cstat == TXN_UNEXPECTED)
goto not_right;
return (ret);
} else if (ret == ENOENT) {
if (try_inmem == 0 &&
opcode != DBREG_PREOPEN && opcode != DBREG_REOPEN &&
opcode != DBREG_XREOPEN) {
if ((ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0)
return (ret);
try_inmem = 1;
goto retry_inmem;
} else if (try_inmem != 0)
CLR_INMEM(dbp);
if (id != TXN_INVALID && (ret = __db_txnlist_update(env,
info, id, TXN_UNEXPECTED, NULL, &ret_stat, 1)) != 0)
goto not_right;
if (dbp->log_filename == NULL &&
(ret = __dbreg_setup(dbp, name, NULL, id)) != 0)
return (ret);
ret = __dbreg_assign_id(dbp, ndx, 1);
return (ret);
}
not_right:
if ((t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0)
return (ret == 0 ? t_ret : ret);
if ((t_ret = __dbreg_add_dbentry(env, lp, NULL, ndx)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
static int
__dbreg_check_master(env, uid, name)
ENV *env;
u_int8_t *uid;
char *name;
{
DB *dbp;
int ret;
if ((ret = __db_create_internal(&dbp, env, 0)) != 0)
return (ret);
F_SET(dbp, DB_AM_RECOVER);
ret = __db_open(dbp, NULL, NULL,
name, NULL, DB_BTREE, 0, DB_MODE_600, 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_LOG *dblp;
DB_TXN *txn;
ENV *env;
FNAME *fnp;
LOG *lp;
int32_t id;
int ret;
env = dbp->env;
DB_ASSERT(env, IS_REP_MASTER(env) || F_ISSET(dbp, DB_AM_NOT_DURABLE));
env = dbp->env;
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
fnp = dbp->log_filename;
MUTEX_LOCK(env, lp->mtx_filelist);
if (fnp->id != DB_LOGFILEID_INVALID) {
MUTEX_UNLOCK(env, lp->mtx_filelist);
return (0);
}
id = DB_LOGFILEID_INVALID;
if (fnp->old_id != DB_LOGFILEID_INVALID &&
(ret = __dbreg_revoke_id(dbp, 1, DB_LOGFILEID_INVALID)) != 0)
goto err;
if ((ret = __txn_begin(env, NULL, NULL, &txn, DB_IGNORE_LEASE)) != 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(env, lp->mtx_filelist);
return (ret);
}