2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char copyright
[] =
12 "@(#) Copyright (c) 1996, 1997, 1998\n\
13 Sleepycat Software Inc. All rights reserved.\n";
14 static const char sccsid
[] = "@(#)db_apprec.c 10.30 (Sleepycat) 5/3/98";
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 *, u_int32_t));
41 __db_apprec(dbenv
, flags
)
47 DB_LSN ckp_lsn
, first_lsn
, lsn
;
55 /* Initialize the transaction list. */
56 if ((ret
= __db_txnlist_init(&txninfo
)) != 0)
60 * Save the state of the thread flag -- we don't need it on at the
61 * moment because we're single-threaded until recovery is complete.
63 is_thread
= F_ISSET(lp
, DB_AM_THREAD
);
64 F_CLR(lp
, DB_AM_THREAD
);
67 * Recovery is done in three passes:
69 * Read forward through the log from the last checkpoint to the
70 * end of the log, opening and closing files so that at the end
71 * of the log we have the "current" set of files open.
73 * Read backward through the log undoing any uncompleted TXNs.
74 * If doing catastrophic recovery, we read to the beginning of
75 * the log, otherwise, to the most recent checkpoint that occurs
76 * before the most recent checkpoint LSN, which is returned by
77 * __log_findckp(). During this pass, checkpoint file information
78 * is ignored, and file openings and closings are undone.
80 * Read forward through the log from the LSN found in pass #2,
81 * redoing any committed TXNs. During this pass, checkpoint
82 * file information is ignored, and file openings and closings
87 * Find the last checkpoint in the log. This is the point from which
88 * we want to begin pass #1 (the TXN_OPENFILES pass).
90 memset(&data
, 0, sizeof(data
));
91 if ((ret
= log_get(lp
, &ckp_lsn
, &data
, DB_CHECKPOINT
)) != 0) {
93 * If we don't find a checkpoint, start from the beginning.
94 * If that fails, we're done. Note, we do not require that
95 * there be log records if we're performing recovery.
97 if ((ret
= log_get(lp
, &ckp_lsn
, &data
, DB_FIRST
)) != 0) {
98 if (ret
== DB_NOTFOUND
)
101 __db_err(dbenv
, "First log record not found");
107 * Now, ckp_lsn is either the lsn of the last checkpoint or the lsn
108 * of the first record in the log. Begin the TXN_OPENFILES pass from
109 * that lsn, and proceed to the end of the log.
113 ret
= __db_dispatch(lp
, &data
, &lsn
, TXN_OPENFILES
, txninfo
);
114 if (ret
!= 0 && ret
!= DB_TXN_CKP
)
116 if ((ret
= log_get(lp
, &lsn
, &data
, DB_NEXT
)) != 0) {
117 if (ret
== DB_NOTFOUND
)
126 * Before we can begin pass #2, backward roll phase, we determine how
127 * far back in the log to recover. If we are doing catastrophic
128 * recovery, then we go as far back as we have files. If we are
129 * doing normal recovery, we go as back to the most recent checkpoint
130 * that occurs before the most recent checkpoint LSN.
132 if (LF_ISSET(DB_RECOVER_FATAL
)) {
135 if ((ret
= __log_findckp(lp
, &first_lsn
)) == DB_NOTFOUND
) {
137 * We don't require that log files exist if recovery
144 if (dbenv
->db_verbose
)
145 __db_err(lp
->dbenv
, "Recovery starting from [%lu][%lu]",
146 (u_long
)first_lsn
.file
, (u_long
)first_lsn
.offset
);
148 for (ret
= log_get(lp
, &lsn
, &data
, DB_LAST
);
149 ret
== 0 && log_compare(&lsn
, &first_lsn
) > 0;
150 ret
= log_get(lp
, &lsn
, &data
, DB_PREV
)) {
151 ret
= __db_dispatch(lp
,
152 &data
, &lsn
, TXN_BACKWARD_ROLL
, txninfo
);
154 if (ret
!= DB_TXN_CKP
)
160 if (ret
!= 0 && ret
!= DB_NOTFOUND
)
166 for (ret
= log_get(lp
, &lsn
, &data
, DB_NEXT
);
167 ret
== 0; ret
= log_get(lp
, &lsn
, &data
, DB_NEXT
)) {
168 ret
= __db_dispatch(lp
, &data
, &lsn
, TXN_FORWARD_ROLL
, txninfo
);
170 if (ret
!= DB_TXN_CKP
)
176 if (ret
!= DB_NOTFOUND
)
179 /* Now close all the db files that are open. */
180 __log_close_files(lp
);
183 * Now set the last checkpoint lsn and the current time,
184 * take a checkpoint, and reset the txnid.
187 dbenv
->tx_info
->region
->last_ckp
= ckp_lsn
;
188 dbenv
->tx_info
->region
->time_ckp
= (u_int32_t
)now
;
189 if ((ret
= txn_checkpoint(dbenv
->tx_info
, 0, 0)) != 0)
191 dbenv
->tx_info
->region
->last_txnid
= TXN_MINIMUM
;
193 if (dbenv
->db_verbose
) {
194 __db_err(lp
->dbenv
, "Recovery complete at %.24s", ctime(&now
));
195 __db_err(lp
->dbenv
, "%s %lx %s [%lu][%lu]",
196 "Maximum transaction id",
197 ((DB_TXNHEAD
*)txninfo
)->maxid
,
198 "Recovery checkpoint",
199 (u_long
)dbenv
->tx_info
->region
->last_ckp
.file
,
200 (u_long
)dbenv
->tx_info
->region
->last_ckp
.offset
);
204 msgerr
: __db_err(dbenv
, "Recovery function for LSN %lu %lu failed",
205 (u_long
)lsn
.file
, (u_long
)lsn
.offset
);
208 out
: F_SET(lp
, is_thread
);
209 __db_txnlist_end(txninfo
);