summaryrefslogtreecommitdiff
path: root/db/txn/txn_recover.c
diff options
context:
space:
mode:
Diffstat (limited to 'db/txn/txn_recover.c')
-rw-r--r--db/txn/txn_recover.c222
1 files changed, 140 insertions, 82 deletions
diff --git a/db/txn/txn_recover.c b/db/txn/txn_recover.c
index 8f02264c0..753a84dd3 100644
--- a/db/txn/txn_recover.c
+++ b/db/txn/txn_recover.c
@@ -1,14 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2001
+ * Copyright (c) 2001-2003
* Sleepycat Software. All rights reserved.
*/
#include "db_config.h"
#ifndef lint
-static const char revid[] = "Id: txn_recover.c,v 1.12 2001/04/27 15:48:16 bostic Exp ";
+static const char revid[] = "$Id: txn_recover.c,v 1.43 2003/09/16 20:50:17 sue Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -17,27 +17,22 @@ static const char revid[] = "Id: txn_recover.c,v 1.12 2001/04/27 15:48:16 bostic
#include <string.h>
#endif
-#ifdef HAVE_RPC
-#include "db_server.h"
-#endif
-
#include "db_int.h"
-#include "txn.h"
-#include "db_page.h"
-#include "log.h"
-#include "db_auto.h"
-#include "crdel_auto.h"
-#include "db_ext.h"
-
-#ifdef HAVE_RPC
-#include "rpc_client_ext.h"
-#endif
+#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"
/*
* __txn_continue
* Fill in the fields of the local transaction structure given
* the detail transaction structure.
- * XXX I'm not sure that we work correctly with nested txns.
+ *
+ * XXX
+ * I'm not sure that we work correctly with nested txns.
*
* PUBLIC: void __txn_continue __P((DB_ENV *, DB_TXN *, TXN_DETAIL *, size_t));
*/
@@ -52,8 +47,17 @@ __txn_continue(env, txnp, td, off)
txnp->parent = NULL;
txnp->last_lsn = td->last_lsn;
txnp->txnid = td->txnid;
- txnp->off = off;
+ 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);
}
/*
@@ -97,26 +101,60 @@ __txn_map_gid(dbenv, gid, tdp, offp)
}
/*
- * txn_recover --
- * Public interface to retrieve the list of prepared, but not yet
- * commited transactions. See __txn_get_prepared for details. This
- * function and __db_xa_recover both wrap that one.
+ * __txn_recover_pp --
+ * DB_ENV->txn_recover pre/post processing.
*
- * EXTERN: int txn_recover
- * EXTERN: __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t));
+ * PUBLIC: int __txn_recover_pp
+ * PUBLIC: __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t));
*/
int
-txn_recover(dbenv, preplist, count, retp, flags)
+__txn_recover_pp(dbenv, preplist, count, retp, flags)
DB_ENV *dbenv;
DB_PREPLIST *preplist;
long count, *retp;
u_int32_t flags;
{
-#ifdef HAVE_RPC
- if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
- return (__dbcl_txn_recover(dbenv,
- preplist, count, retp, flags));
-#endif
+ 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);
+}
+
+/*
+ * __txn_recover --
+ * DB_ENV->txn_recover.
+ *
+ * PUBLIC: int __txn_recover
+ * PUBLIC: __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t));
+ */
+int
+__txn_recover(dbenv, preplist, count, retp, flags)
+ DB_ENV *dbenv;
+ DB_PREPLIST *preplist;
+ long count, *retp;
+ u_int32_t flags;
+{
+ /*
+ * Public API to retrieve the list of prepared, but not yet committed
+ * transactions. See __txn_get_prepared for details. This function
+ * and __db_xa_recover both wrap that one.
+ */
return (__txn_get_prepared(dbenv, NULL, preplist, count, retp, flags));
}
@@ -142,24 +180,27 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags)
long *retp;
u_int32_t flags;
{
- XID *xidp;
+ DBT data;
+ DB_LOGC *logc;
+ DB_LSN min, open_lsn;
DB_PREPLIST *prepp;
- TXN_DETAIL *td;
DB_TXNMGR *mgr;
DB_TXNREGION *tmr;
- DB_LSN min, open_lsn;
- DBT data;
+ TXN_DETAIL *td;
+ XID *xidp;
__txn_ckp_args *ckp_args;
- int nrestores, open_files, ret;
+ long i;
+ int nrestores, open_files, ret, t_ret;
void *txninfo;
- ret = 0;
*retp = 0;
- xidp = xids;
+
+ logc = NULL;
+ MAX_LSN(min);
prepp = txns;
+ xidp = xids;
+ nrestores = ret = 0;
open_files = 1;
- nrestores = 0;
- MAX_LSN(min);
/*
* If we are starting a scan, then we traverse the active transaction
@@ -184,13 +225,13 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags)
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_RESTORED))
+ if (F_ISSET(td, TXN_DTL_RESTORED))
nrestores++;
- if (F_ISSET(td, TXN_COLLECTED))
+ if (F_ISSET(td, TXN_DTL_COLLECTED))
open_files = 0;
- F_CLR(td, TXN_COLLECTED);
+ F_CLR(td, TXN_DTL_COLLECTED);
}
-
+ mgr->n_discards = 0;
} else
open_files = 0;
@@ -198,7 +239,8 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags)
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_COLLECTED))
+ if (td->status != TXN_PREPARED ||
+ F_ISSET(td, TXN_DTL_COLLECTED))
continue;
if (xids != NULL) {
@@ -211,10 +253,13 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags)
if (txns != NULL) {
if ((ret = __os_calloc(dbenv,
- 1, sizeof(DB_TXN), &prepp->txn)) != 0)
- break;
+ 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++;
}
@@ -223,61 +268,74 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags)
min = td->begin_lsn;
(*retp)++;
- F_SET(td, TXN_COLLECTED);
+ F_SET(td, TXN_DTL_COLLECTED);
}
R_UNLOCK(dbenv, &mgr->reginfo);
- if (open_files && nrestores &&
- ret == 0 && *retp != 0 && !IS_MAX_LSN(min)) {
+ /*
+ * Now link all the transactions into the transaction manager's list.
+ */
+ 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)) {
/*
* Figure out the last checkpoint before the smallest
* start_lsn in the region.
*/
F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
+
+ if ((ret = __log_cursor(dbenv, &logc)) != 0)
+ goto err;
+
memset(&data, 0, sizeof(data));
- for (ret = log_get(dbenv, &open_lsn, &data, DB_CHECKPOINT);
- ret == 0 && log_compare(&min, &open_lsn) < 0;
- ret = log_get(dbenv, &open_lsn, &data, DB_SET)) {
-
- /* Format the log record. */
- if ((ret = __txn_ckp_read(dbenv,
- data.data, &ckp_args)) != 0) {
- __db_err(dbenv,
- "Invalid checkpoint record at [%ld][%ld]\n",
- (u_long)open_lsn.file,
- (u_long)open_lsn.offset);
- goto out;
+ 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) {
+ /* Format the log record. */
+ 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);
}
- open_lsn = ckp_args->last_ckp;
- __os_free(dbenv, ckp_args, sizeof(*ckp_args));
- }
/*
- * There are three ways we got here.
- * We got a DB_NOTFOUND -- we need to read the first log record.
- * We found a checkpoint before min. We're done.
- * We found a checkpoint after min who's last_ckp is 0. We
+ * There are three ways by which we may have gotten here.
+ * - We got a DB_NOTFOUND -- we need to read the first
+ * log record.
+ * - We found a checkpoint before min. We're done.
+ * - We found a checkpoint after min who's last_ckp is 0. We
* need to start at the beginning of the log.
*/
-
- if ((ret == DB_NOTFOUND || IS_ZERO_LSN(open_lsn)) &&
- (ret = log_get(dbenv, &open_lsn, &data, DB_FIRST)) != 0) {
- __db_err(dbenv, "No log records.");
- goto out;
+ 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, &txninfo)) != 0)
- goto out;
- ret = __env_openfiles(dbenv,
+ 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);
- F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
}
- if (0) {
-out: F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
- }
- return (ret);
-}
+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);
+}