#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: txn_recover.c,v 1.2 2004/03/30 01:24:47 jtownsen Exp $";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/txn.h"
#include "dbinc/db_page.h"
#include "dbinc/db_dispatch.h"
#include "dbinc/log.h"
#include "dbinc_auto/db_auto.h"
#include "dbinc_auto/crdel_auto.h"
#include "dbinc_auto/db_ext.h"
void
__txn_continue(env, txnp, td, off)
DB_ENV *env;
DB_TXN *txnp;
TXN_DETAIL *td;
size_t off;
{
txnp->mgrp = env->tx_handle;
txnp->parent = NULL;
txnp->last_lsn = td->last_lsn;
txnp->txnid = td->txnid;
txnp->off = (roff_t)off;
txnp->abort = __txn_abort;
txnp->commit = __txn_commit;
txnp->discard = __txn_discard;
txnp->id = __txn_id;
txnp->prepare = __txn_prepare;
txnp->flags = 0;
if (F_ISSET(td, TXN_DTL_RESTORED))
F_SET(txnp, TXN_RESTORED);
}
int
__txn_map_gid(dbenv, gid, tdp, offp)
DB_ENV *dbenv;
u_int8_t *gid;
TXN_DETAIL **tdp;
size_t *offp;
{
DB_TXNMGR *mgr;
DB_TXNREGION *tmr;
mgr = dbenv->tx_handle;
tmr = mgr->reginfo.primary;
R_LOCK(dbenv, &mgr->reginfo);
for (*tdp = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail);
*tdp != NULL;
*tdp = SH_TAILQ_NEXT(*tdp, links, __txn_detail))
if (memcmp(gid, (*tdp)->xid, sizeof((*tdp)->xid)) == 0)
break;
R_UNLOCK(dbenv, &mgr->reginfo);
if (*tdp == NULL)
return (EINVAL);
*offp = R_OFFSET(&mgr->reginfo, *tdp);
return (0);
}
int
__txn_recover_pp(dbenv, preplist, count, retp, flags)
DB_ENV *dbenv;
DB_PREPLIST *preplist;
long count, *retp;
u_int32_t flags;
{
int rep_check, ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(
dbenv, dbenv->tx_handle, "txn_recover", DB_INIT_TXN);
if (F_ISSET((DB_TXNREGION *)
((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary,
TXN_IN_RECOVERY)) {
__db_err(dbenv, "operation not permitted while in recovery");
return (EINVAL);
}
rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
if (rep_check)
__env_rep_enter(dbenv);
ret = __txn_recover(dbenv, preplist, count, retp, flags);
if (rep_check)
__env_rep_exit(dbenv);
return (ret);
}
int
__txn_recover(dbenv, preplist, count, retp, flags)
DB_ENV *dbenv;
DB_PREPLIST *preplist;
long count, *retp;
u_int32_t flags;
{
return (__txn_get_prepared(dbenv, NULL, preplist, count, retp, flags));
}
int
__txn_get_prepared(dbenv, xids, txns, count, retp, flags)
DB_ENV *dbenv;
XID *xids;
DB_PREPLIST *txns;
long count;
long *retp;
u_int32_t flags;
{
DBT data;
DB_LOGC *logc;
DB_LSN min, open_lsn;
DB_PREPLIST *prepp;
DB_TXNMGR *mgr;
DB_TXNREGION *tmr;
TXN_DETAIL *td;
XID *xidp;
__txn_ckp_args *ckp_args;
long i;
int nrestores, open_files, ret, t_ret;
void *txninfo;
*retp = 0;
logc = NULL;
MAX_LSN(min);
prepp = txns;
xidp = xids;
nrestores = ret = 0;
open_files = 1;
mgr = dbenv->tx_handle;
tmr = mgr->reginfo.primary;
R_LOCK(dbenv, &mgr->reginfo);
if (flags == DB_FIRST) {
for (td = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail);
td != NULL;
td = SH_TAILQ_NEXT(td, links, __txn_detail)) {
if (F_ISSET(td, TXN_DTL_RESTORED))
nrestores++;
if (F_ISSET(td, TXN_DTL_COLLECTED))
open_files = 0;
F_CLR(td, TXN_DTL_COLLECTED);
}
mgr->n_discards = 0;
} else
open_files = 0;
for (td = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail);
td != NULL && *retp < count;
td = SH_TAILQ_NEXT(td, links, __txn_detail)) {
if (td->status != TXN_PREPARED ||
F_ISSET(td, TXN_DTL_COLLECTED))
continue;
if (xids != NULL) {
xidp->formatID = td->format;
xidp->gtrid_length = td->gtrid;
xidp->bqual_length = td->bqual;
memcpy(xidp->data, td->xid, sizeof(td->xid));
xidp++;
}
if (txns != NULL) {
if ((ret = __os_calloc(dbenv,
1, sizeof(DB_TXN), &prepp->txn)) != 0) {
R_UNLOCK(dbenv, &mgr->reginfo);
goto err;
}
__txn_continue(dbenv,
prepp->txn, td, R_OFFSET(&mgr->reginfo, td));
F_SET(prepp->txn, TXN_MALLOC);
memcpy(prepp->gid, td->xid, sizeof(td->xid));
prepp++;
}
if (log_compare(&td->begin_lsn, &min) < 0)
min = td->begin_lsn;
(*retp)++;
F_SET(td, TXN_DTL_COLLECTED);
}
R_UNLOCK(dbenv, &mgr->reginfo);
if (txns != NULL) {
MUTEX_THREAD_LOCK(dbenv, mgr->mutexp);
for (i = 0; i < *retp; i++)
TAILQ_INSERT_TAIL(&mgr->txn_chain, txns[i].txn, links);
MUTEX_THREAD_UNLOCK(dbenv, mgr->mutexp);
}
if (open_files && nrestores && *retp != 0 && !IS_MAX_LSN(min)) {
F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
if ((ret = __log_cursor(dbenv, &logc)) != 0)
goto err;
memset(&data, 0, sizeof(data));
if ((ret = __txn_getckp(dbenv, &open_lsn)) == 0)
while (!IS_ZERO_LSN(open_lsn) && (ret =
__log_c_get(logc, &open_lsn, &data, DB_SET)) == 0 &&
log_compare(&min, &open_lsn) < 0) {
if ((ret = __txn_ckp_read(dbenv,
data.data, &ckp_args)) != 0) {
__db_err(dbenv,
"Invalid checkpoint record at [%lu][%lu]",
(u_long)open_lsn.file,
(u_long)open_lsn.offset);
goto err;
}
open_lsn = ckp_args->last_ckp;
__os_free(dbenv, ckp_args);
}
if ((ret == DB_NOTFOUND || IS_ZERO_LSN(open_lsn)) && (ret =
__log_c_get(logc, &open_lsn, &data, DB_FIRST)) != 0) {
__db_err(dbenv, "No log records");
goto err;
}
if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txninfo)) != 0)
goto err;
ret = __env_openfiles(dbenv, logc,
txninfo, &data, &open_lsn, NULL, 0, 0);
if (txninfo != NULL)
__db_txnlist_end(dbenv, txninfo);
}
err: F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}