2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)log_findckp.c 10.17 (Sleepycat) 9/17/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
25 #include "common_ext.h"
30 * Looks for the most recent checkpoint that occurs before the most recent
31 * checkpoint LSN, subject to the constraint that there must be at least two
32 * checkpoints. The reason you need two checkpoints is that you might have
33 * crashed during the most recent one and may not have a copy of all the
34 * open files. This is the point from which recovery can start and the
35 * point up to which archival/truncation can take place. Checkpoints in
38 * -------------------------------------------------------------------
39 * | ckp A, ckplsn 100 | .... record .... | ckp B, ckplsn 600 | ...
40 * -------------------------------------------------------------------
43 * If we read what log returns from using the DB_CKP parameter to logput,
44 * we'll get the record at LSN 1000. The checkpoint LSN there is 600.
45 * Now we have to scan backwards looking for a checkpoint before LSN 600.
46 * We find one at 500. This means that we can truncate the log before
47 * 500 or run recovery beginning at 500.
49 * Returns 0 if we find a suitable checkpoint or we retrieved the
50 * first record in the log from which to start.
51 * Returns DB_NOTFOUND if there are no log records.
52 * Returns errno on error.
54 * PUBLIC: int __log_findckp __P((DB_LOG *, DB_LSN *));
57 __log_findckp(lp
, lsnp
)
62 DB_LSN ckp_lsn
, final_ckp
, last_ckp
, next_lsn
;
63 __txn_ckp_args
*ckp_args
;
66 verbose
= lp
->dbenv
!= NULL
&& lp
->dbenv
->db_verbose
!= 0;
69 * Need to find the appropriate point from which to begin
72 memset(&data
, 0, sizeof(data
));
73 if (F_ISSET(lp
, DB_AM_THREAD
))
74 F_SET(&data
, DB_DBT_MALLOC
);
76 if ((ret
= log_get(lp
, &last_ckp
, &data
, DB_CHECKPOINT
)) != 0) {
86 if (F_ISSET(lp
, DB_AM_THREAD
))
87 __os_free(data
.data
, data
.size
);
89 if ((ret
= log_get(lp
, &next_lsn
, &data
, DB_SET
)) != 0)
91 if ((ret
= __txn_ckp_read(data
.data
, &ckp_args
)) != 0) {
92 if (F_ISSET(lp
, DB_AM_THREAD
))
93 __os_free(data
.data
, data
.size
);
96 if (IS_ZERO_LSN(ckp_lsn
))
97 ckp_lsn
= ckp_args
->ckp_lsn
;
99 __db_err(lp
->dbenv
, "Checkpoint at: [%lu][%lu]",
100 (u_long
)last_ckp
.file
, (u_long
)last_ckp
.offset
);
101 __db_err(lp
->dbenv
, "Checkpoint LSN: [%lu][%lu]",
102 (u_long
)ckp_args
->ckp_lsn
.file
,
103 (u_long
)ckp_args
->ckp_lsn
.offset
);
104 __db_err(lp
->dbenv
, "Previous checkpoint: [%lu][%lu]",
105 (u_long
)ckp_args
->last_ckp
.file
,
106 (u_long
)ckp_args
->last_ckp
.offset
);
109 next_lsn
= ckp_args
->last_ckp
;
110 __os_free(ckp_args
, sizeof(*ckp_args
));
113 * Keep looping until either you 1) run out of checkpoints,
114 * 2) you've found a checkpoint before the most recent
115 * checkpoint's LSN and you have at least 2 checkpoints.
117 } while (!IS_ZERO_LSN(next_lsn
) &&
118 (log_compare(&last_ckp
, &ckp_lsn
) > 0 ||
119 log_compare(&final_ckp
, &last_ckp
) == 0));
121 if (F_ISSET(lp
, DB_AM_THREAD
))
122 __os_free(data
.data
, data
.size
);
125 * At this point, either, next_lsn is ZERO or ckp_lsn is the
126 * checkpoint lsn and last_ckp is the LSN of the last checkpoint
127 * before ckp_lsn. If the compare in the loop is still true, then
128 * next_lsn must be 0 and we need to roll forward from the
129 * beginning of the log.
131 if (log_compare(&last_ckp
, &ckp_lsn
) > 0 ||
132 log_compare(&final_ckp
, &last_ckp
) == 0) {
133 get_first
: if ((ret
= log_get(lp
, &last_ckp
, &data
, DB_FIRST
)) != 0)
135 if (F_ISSET(lp
, DB_AM_THREAD
))
136 __os_free(data
.data
, data
.size
);
140 return (IS_ZERO_LSN(last_ckp
) ? DB_NOTFOUND
: 0);