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.15 (Sleepycat) 4/26/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. This is the point from which recovery can start and the
32 * point up to which archival/truncation can take place. Checkpoints in
35 * -------------------------------------------------------------------
36 * | ckp A, ckplsn 100 | .... record .... | ckp B, ckplsn 600 | ...
37 * -------------------------------------------------------------------
40 * If we read what log returns from using the DB_CKP parameter to logput,
41 * we'll get the record at LSN 1000. The checkpoint LSN there is 600.
42 * Now we have to scan backwards looking for a checkpoint before LSN 600.
43 * We find one at 500. This means that we can truncate the log before
44 * 500 or run recovery beginning at 500.
46 * Returns 0 if we find a suitable checkpoint or we retrieved the
47 * first record in the log from which to start.
48 * Returns DB_NOTFOUND if there are no log records.
49 * Returns errno on error.
51 * PUBLIC: int __log_findckp __P((DB_LOG *, DB_LSN *));
54 __log_findckp(lp
, lsnp
)
59 DB_LSN ckp_lsn
, last_ckp
, next_lsn
;
60 __txn_ckp_args
*ckp_args
;
63 verbose
= lp
->dbenv
!= NULL
&& lp
->dbenv
->db_verbose
!= 0;
66 * Need to find the appropriate point from which to begin
69 memset(&data
, 0, sizeof(data
));
70 if (F_ISSET(lp
, DB_AM_THREAD
))
71 F_SET(&data
, DB_DBT_MALLOC
);
73 if ((ret
= log_get(lp
, &last_ckp
, &data
, DB_CHECKPOINT
)) != 0) {
82 if (F_ISSET(lp
, DB_AM_THREAD
))
85 if ((ret
= log_get(lp
, &next_lsn
, &data
, DB_SET
)) != 0)
87 if ((ret
= __txn_ckp_read(data
.data
, &ckp_args
)) != 0) {
88 if (F_ISSET(lp
, DB_AM_THREAD
))
92 if (IS_ZERO_LSN(ckp_lsn
))
93 ckp_lsn
= ckp_args
->ckp_lsn
;
95 __db_err(lp
->dbenv
, "Checkpoint at: [%lu][%lu]",
96 (u_long
)last_ckp
.file
, (u_long
)last_ckp
.offset
);
97 __db_err(lp
->dbenv
, "Checkpoint LSN: [%lu][%lu]",
98 (u_long
)ckp_args
->ckp_lsn
.file
,
99 (u_long
)ckp_args
->ckp_lsn
.offset
);
100 __db_err(lp
->dbenv
, "Previous checkpoint: [%lu][%lu]",
101 (u_long
)ckp_args
->last_ckp
.file
,
102 (u_long
)ckp_args
->last_ckp
.offset
);
105 next_lsn
= ckp_args
->last_ckp
;
107 } while (!IS_ZERO_LSN(next_lsn
) &&
108 log_compare(&last_ckp
, &ckp_lsn
) > 0);
110 if (F_ISSET(lp
, DB_AM_THREAD
))
111 __db_free(data
.data
);
114 * At this point, either, next_lsn is ZERO or ckp_lsn is the
115 * checkpoint lsn and last_ckp is the LSN of the last checkpoint
116 * before ckp_lsn. If the compare in the loop is still true, then
117 * next_lsn must be 0 and we need to roll forward from the
118 * beginning of the log.
120 if (log_compare(&last_ckp
, &ckp_lsn
) > 0) {
121 get_first
: if ((ret
= log_get(lp
, &last_ckp
, &data
, DB_FIRST
)) != 0)
123 if (F_ISSET(lp
, DB_AM_THREAD
))
124 __db_free(data
.data
);
128 return (IS_ZERO_LSN(last_ckp
) ? DB_NOTFOUND
: 0);