#include "config.h"
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1996, 1997, 1998\n\
Sleepycat Software Inc. All rights reserved.\n";
static const char sccsid[] = "@(#)db_apprec.c 10.33 (Sleepycat) 10/5/98";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#endif
#include "db_int.h"
#include "shqueue.h"
#include "db_page.h"
#include "db_dispatch.h"
#include "db_am.h"
#include "log.h"
#include "txn.h"
#include "common_ext.h"
int
__db_apprec(dbenv, flags)
DB_ENV *dbenv;
u_int32_t flags;
{
DBT data;
DB_LOG *lp;
DB_LSN ckp_lsn, first_lsn, lsn, open_lsn;
__txn_ckp_args *ckp_args;
time_t now;
u_int32_t is_thread;
int ret;
void *txninfo;
lp = dbenv->lg_info;
if ((ret = __db_txnlist_init(&txninfo)) != 0)
return (ret);
is_thread = F_ISSET(lp, DB_AM_THREAD);
F_CLR(lp, DB_AM_THREAD);
memset(&data, 0, sizeof(data));
ckp_args = NULL;
if ((ret = log_get(lp, &ckp_lsn, &data, DB_CHECKPOINT)) != 0) {
first: if ((ret = log_get(lp, &ckp_lsn, &data, DB_FIRST)) != 0) {
if (ret == DB_NOTFOUND)
ret = 0;
else
__db_err(dbenv, "First log record not found");
goto out;
}
open_lsn = ckp_lsn;
} else if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
__db_err(dbenv, "Invalid checkpoint record at [%ld][%ld]\n",
(u_long)ckp_lsn.file, (u_long)ckp_lsn.offset);
goto out;
} else if (IS_ZERO_LSN(ckp_args->last_ckp) ||
(ret = log_get(lp, &ckp_args->last_ckp, &data, DB_SET)) != 0)
goto first;
else
open_lsn = ckp_args->last_ckp;
lsn = open_lsn;
for (;;) {
if (dbenv->tx_recover != NULL)
ret = dbenv->tx_recover(lp,
&data, &lsn, TXN_OPENFILES, txninfo);
else
ret = __db_dispatch(lp,
&data, &lsn, TXN_OPENFILES, txninfo);
if (ret != 0 && ret != DB_TXN_CKP)
goto msgerr;
if ((ret = log_get(lp, &lsn, &data, DB_NEXT)) != 0) {
if (ret == DB_NOTFOUND)
break;
goto out;
}
}
if (LF_ISSET(DB_RECOVER_FATAL)) {
ZERO_LSN(first_lsn);
} else
if ((ret = __log_findckp(lp, &first_lsn)) == DB_NOTFOUND) {
ret = 0;
goto out;
}
if (dbenv->db_verbose)
__db_err(lp->dbenv, "Recovery starting from [%lu][%lu]",
(u_long)first_lsn.file, (u_long)first_lsn.offset);
for (ret = log_get(lp, &lsn, &data, DB_LAST);
ret == 0 && log_compare(&lsn, &first_lsn) > 0;
ret = log_get(lp, &lsn, &data, DB_PREV)) {
if (dbenv->tx_recover != NULL)
ret = dbenv->tx_recover(lp,
&data, &lsn, TXN_BACKWARD_ROLL, txninfo);
else
ret = __db_dispatch(lp,
&data, &lsn, TXN_BACKWARD_ROLL, txninfo);
if (ret != 0)
if (ret != DB_TXN_CKP)
goto msgerr;
else
ret = 0;
}
if (ret != 0 && ret != DB_NOTFOUND)
goto out;
for (ret = log_get(lp, &lsn, &data, DB_NEXT);
ret == 0; ret = log_get(lp, &lsn, &data, DB_NEXT)) {
if (dbenv->tx_recover != NULL)
ret = dbenv->tx_recover(lp,
&data, &lsn, TXN_FORWARD_ROLL, txninfo);
else
ret = __db_dispatch(lp,
&data, &lsn, TXN_FORWARD_ROLL, txninfo);
if (ret != 0)
if (ret != DB_TXN_CKP)
goto msgerr;
else
ret = 0;
}
if (ret != DB_NOTFOUND)
goto out;
__log_close_files(lp);
(void)time(&now);
dbenv->tx_info->region->last_ckp = ckp_lsn;
dbenv->tx_info->region->time_ckp = (u_int32_t)now;
if ((ret = txn_checkpoint(dbenv->tx_info, 0, 0)) != 0)
goto out;
dbenv->tx_info->region->last_txnid = TXN_MINIMUM;
if (dbenv->db_verbose) {
__db_err(lp->dbenv, "Recovery complete at %.24s", ctime(&now));
__db_err(lp->dbenv, "%s %lx %s [%lu][%lu]",
"Maximum transaction id",
((DB_TXNHEAD *)txninfo)->maxid,
"Recovery checkpoint",
(u_long)dbenv->tx_info->region->last_ckp.file,
(u_long)dbenv->tx_info->region->last_ckp.offset);
}
if (0) {
msgerr: __db_err(dbenv, "Recovery function for LSN %lu %lu failed",
(u_long)lsn.file, (u_long)lsn.offset);
}
out: F_SET(lp, is_thread);
__db_txnlist_end(txninfo);
if (ckp_args != NULL)
__os_free(ckp_args, sizeof(*ckp_args));
return (ret);
}