2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
11 static const char copyright[] =
12 "@(#) Copyright (c) 1997\n\
13 Sleepycat Software Inc. All rights reserved.\n";
14 static const char sccsid[] = "@(#)db_apprec.c 10.18 (Sleepycat) 9/30/97";
17 #ifndef NO_SYSTEM_INCLUDES
18 #include <sys/types.h>
28 #include "db_dispatch.h"
32 #include "common_ext.h"
38 * PUBLIC: int __db_apprec __P((DB_ENV *, int));
41 __db_apprec(dbenv, flags)
47 DB_LSN ckp_lsn, first_lsn, lsn, tmp_lsn;
49 int first_flag, is_thread, ret;
54 /* Initialize the transaction list. */
55 if ((ret = __db_txnlist_init(&txninfo)) != 0)
59 * Save the state of the thread flag -- we don't need it on at the
60 * moment because we're single-threaded until recovery is complete.
62 is_thread = F_ISSET(lp, DB_AM_THREAD);
63 F_CLR(lp, DB_AM_THREAD);
66 * Read forward through the log, opening the appropriate files so that
67 * we can call recovery routines. In general, we start at the last
68 * checkpoint prior to the last checkpointed LSN. For catastrophic
69 * recovery, we begin at the first LSN that appears in any log file
70 * (log_get figures this out for us when we pass it the DB_FIRST flag).
72 if (LF_ISSET(DB_RECOVER_FATAL))
73 first_flag = DB_FIRST;
75 if ((ret = __log_findckp(lp, &lsn)) == DB_NOTFOUND) {
82 /* If we're a threaded application, we have to allocate space. */
83 memset(&data, 0, sizeof(data));
84 if ((ret = log_get(lp, &lsn, &data, first_flag)) != 0) {
85 __db_err(dbenv, "Failure: unable to get log record");
86 if (first_flag == DB_SET)
87 __db_err(dbenv, "Retrieving LSN %lu %lu",
88 (u_long)lsn.file, (u_long)lsn.offset);
90 __db_err(dbenv, "Retrieving first LSN");
96 ret = __db_dispatch(lp, &data, &lsn, TXN_OPENFILES, txninfo);
97 if (ret != 0 && ret != DB_TXN_CKP)
100 log_get(dbenv->lg_info, &lsn, &data, DB_NEXT)) != 0) {
101 if (ret != DB_NOTFOUND)
108 * Initialize the ckp_lsn to 0,0. If we never find a valid
109 * checkpoint in the log, then leaving ckp_lsn at 0,0 is correct.
112 for (ret = log_get(lp, &lsn, &data, DB_LAST);
113 ret == 0 && log_compare(&lsn, &first_lsn) > 0;
114 ret = log_get(lp,&lsn, &data, DB_PREV)) {
116 ret = __db_dispatch(lp,
117 &data, &lsn, TXN_BACKWARD_ROLL, txninfo);
118 if (ret == DB_TXN_CKP) {
119 if (IS_ZERO_LSN(ckp_lsn))
125 if (ret != 0 && ret != DB_NOTFOUND)
128 for (ret = log_get(lp, &lsn, &data, DB_NEXT);
129 ret == 0; ret = log_get(lp, &lsn, &data, DB_NEXT)) {
130 ret = __db_dispatch(lp, &data, &lsn, TXN_FORWARD_ROLL, txninfo);
131 if (ret == DB_TXN_CKP)
136 if (ret != DB_NOTFOUND)
139 /* Now close all the db files that are open. */
140 __log_close_files(lp);
143 * Now set the maximum transaction id, set the last checkpoint lsn,
144 * and the current time. Then take a checkpoint.
147 dbenv->tx_info->region->last_txnid = ((__db_txnhead *)txninfo)->maxid;
148 dbenv->tx_info->region->last_ckp = ckp_lsn;
149 dbenv->tx_info->region->time_ckp = (u_int32_t)now;
150 if ((ret = txn_checkpoint(dbenv->tx_info, 0, 0)) != 0)
153 if (dbenv->db_verbose) {
154 __db_err(lp->dbenv, "Recovery complete at %s", ctime(&now));
155 __db_err(lp->dbenv, "%s %lu %s [%lu][%lu]",
156 "Maximum transaction id",
157 (u_long)dbenv->tx_info->region->last_txnid,
158 "Recovery checkpoint",
159 (u_long)dbenv->tx_info->region->last_ckp.file,
160 (u_long)dbenv->tx_info->region->last_ckp.offset);
163 F_SET(lp, is_thread);
166 msgerr: __db_err(dbenv, "Recovery function for LSN %lu %lu failed",
167 (u_long)lsn.file, (u_long)lsn.offset);
169 err: F_SET(lp, is_thread);