#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
#include "dbinc/txn.h"
static int __dbreg_open_file __P((ENV *,
DB_TXN *, __dbreg_register_args *, void *));
int
__dbreg_register_recover(env, dbtp, lsnp, op, info)
ENV *env;
DBT *dbtp;
DB_LSN *lsnp;
db_recops op;
void *info;
{
__dbreg_register_args *argp;
DB_ENTRY *dbe;
DB_LOG *dblp;
DB *dbp;
u_int32_t opcode, status;
int do_close, do_open, do_rem, ret, t_ret;
dblp = env->lg_handle;
dbp = NULL;
#ifdef DEBUG_RECOVER
REC_PRINT(__dbreg_register_print);
#endif
do_open = do_close = 0;
if ((ret = __dbreg_register_read(env, dbtp->data, &argp)) != 0)
goto out;
opcode = FLD_ISSET(argp->opcode, DBREG_OP_MASK);
switch (opcode) {
case DBREG_OPEN:
case DBREG_PREOPEN:
case DBREG_REOPEN:
case DBREG_XOPEN:
case DBREG_XREOPEN:
if ((DB_REDO(op) ||
op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES))
do_open = 1;
else if (opcode != DBREG_REOPEN && opcode != DBREG_XREOPEN)
do_close = 1;
break;
case DBREG_CLOSE:
if (DB_UNDO(op))
do_open = 1;
else
do_close = 1;
break;
case DBREG_RCLOSE:
if (DB_UNDO(op) || op == DB_TXN_POPENFILES)
do_open = 1;
else
do_close = 1;
break;
case DBREG_CHKPNT:
case DBREG_XCHKPNT:
if (DB_UNDO(op) ||
op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES)
do_open = 1;
break;
default:
ret = __db_unknown_path(env, "__dbreg_register_recover");
goto out;
}
if (do_open) {
if (op == DB_TXN_OPENFILES && opcode != DBREG_CHKPNT
&& opcode != DBREG_XCHKPNT)
F_SET(dblp, DBLOG_FORCE_OPEN);
ret = __dbreg_open_file(env,
op == DB_TXN_ABORT || op == DB_TXN_POPENFILES ?
argp->txnp : NULL, argp, info);
if (ret == DB_PAGE_NOTFOUND && argp->meta_pgno != PGNO_BASE_MD)
ret = ENOENT;
if (ret == ENOENT || ret == EINVAL) {
if (DB_REDO(op) && argp->txnp != 0 &&
dblp->dbentry[argp->fileid].deleted) {
dblp->dbentry[argp->fileid].deleted = 0;
ret =
__dbreg_open_file(env, NULL, argp, info);
if (ret == DB_PAGE_NOTFOUND &&
argp->meta_pgno != PGNO_BASE_MD)
ret = ENOENT;
}
if (ret == ENOENT)
ret = 0;
}
F_CLR(dblp, DBLOG_FORCE_OPEN);
}
if (do_close) {
do_rem = 0;
MUTEX_LOCK(env, dblp->mtx_dbreg);
if (argp->fileid < dblp->dbentry_cnt) {
dbe = &dblp->dbentry[argp->fileid];
if (dbe->dbp == NULL && !dbe->deleted) {
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
goto done;
}
if ((dbp = dbe->dbp) != NULL) {
do_rem = (F_ISSET(dbp, DB_AM_RECOVER) ||
F2_ISSET(dbp, DB2_AM_EXCL)) ?
op != DB_TXN_ABORT :
op == DB_TXN_ABORT;
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
} else if (dbe->deleted) {
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
if ((ret = __dbreg_rem_dbentry(
dblp, argp->fileid)) != 0)
goto out;
}
} else
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
if (do_rem && dbp != NULL) {
if (argp->id != TXN_INVALID) {
if ((ret = __db_txnlist_find(env,
info, argp->txnp->txnid, &status))
!= DB_NOTFOUND && ret != 0)
goto out;
if (ret == DB_NOTFOUND || status != TXN_COMMIT)
F_SET(dbp, DB_AM_DISCARD);
ret = 0;
}
if (op == DB_TXN_ABORT) {
if ((t_ret = __db_refresh(dbp,
NULL, DB_NOSYNC, NULL, 0)) != 0 && ret == 0)
ret = t_ret;
} else {
if ((t_ret = __db_close(
dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
}
}
}
done: if (ret == 0)
*lsnp = argp->prev_lsn;
out: if (argp != NULL)
__os_free(env, argp);
return (ret);
}
static int
__dbreg_open_file(env, txn, argp, info)
ENV *env;
DB_TXN *txn;
__dbreg_register_args *argp;
void *info;
{
DB *dbp;
DB_ENTRY *dbe;
DB_LOG *dblp;
u_int32_t id, opcode, status;
int ret;
dblp = env->lg_handle;
opcode = FLD_ISSET(argp->opcode, DBREG_OP_MASK);
MUTEX_LOCK(env, dblp->mtx_dbreg);
if (argp->fileid != DB_LOGFILEID_INVALID &&
argp->fileid < dblp->dbentry_cnt)
dbe = &dblp->dbentry[argp->fileid];
else
dbe = NULL;
if (dbe != NULL) {
if (dbe->deleted) {
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
return (ENOENT);
}
if ((dbp = dbe->dbp) != NULL) {
if (opcode == DBREG_REOPEN ||
opcode == DBREG_XREOPEN ||
!F_ISSET(dbp, DB_AM_OPEN_CALLED) ||
dbp->meta_pgno != argp->meta_pgno ||
argp->name.size == 0 ||
memcmp(dbp->fileid, argp->uid.data,
DB_FILE_ID_LEN) != 0) {
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
(void)__dbreg_revoke_id(dbp, 0,
DB_LOGFILEID_INVALID);
if (F_ISSET(dbp, DB_AM_RECOVER))
(void)__db_close(dbp, NULL, DB_NOSYNC);
goto reopen;
}
DB_ASSERT(env, dbe->dbp == dbp);
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
if (argp != NULL && argp->id != TXN_INVALID &&
(ret = __db_txnlist_update(env, info,
argp->id, TXN_EXPECTED, NULL, &status, 1)) != 0)
return (ret);
return (0);
}
}
MUTEX_UNLOCK(env, dblp->mtx_dbreg);
reopen:
if (argp->name.size == 0) {
(void)__dbreg_add_dbentry(env, dblp, NULL, argp->fileid);
return (ENOENT);
}
if (txn != NULL) {
id = txn->txnid;
memset(txn, 0, sizeof(DB_TXN));
txn->txnid = id;
txn->mgrp = env->tx_handle;
}
return (__dbreg_do_open(env,
txn, dblp, argp->uid.data, argp->name.data, argp->ftype,
argp->fileid, argp->meta_pgno, info, argp->id, opcode));
}