2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid[] = "@(#)log_findckp.c 10.12 (Sleepycat) 10/25/97";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
26 #include "common_ext.h"
31 * Looks for the most recent checkpoint that occurs before the most recent
32 * checkpoint LSN. This is the point from which recovery can start and the
33 * point up to which archival/truncation can take place. Checkpoints in
36 * -------------------------------------------------------------------
37 * | ckp A, ckplsn 100 | .... record .... | ckp B, ckplsn 600 | ...
38 * -------------------------------------------------------------------
41 * If we read what log returns from using the DB_CKP parameter to logput,
42 * we'll get the record at LSN 1000. The checkpoint LSN there is 600.
43 * Now we have to scan backwards looking for a checkpoint before LSN 600.
44 * We find one at 500. This means that we can truncate the log before
45 * 500 or run recovery beginning at 500.
47 * Returns 0 if we find a checkpoint.
48 * Returns errno on error.
49 * Returns DB_NOTFOUND if we could not find a suitable start point and
50 * we should start from the beginning.
52 * PUBLIC: int __log_findckp __P((DB_LOG *, DB_LSN *));
55 __log_findckp(lp, lsnp)
60 DB_LSN ckp_lsn, last_ckp, next_lsn;
61 __txn_ckp_args *ckp_args;
64 verbose = lp->dbenv != NULL && lp->dbenv->db_verbose != 0;
67 * Need to find the appropriate point from which to begin
70 memset(&data, 0, sizeof(data));
71 if (F_ISSET(lp, DB_AM_THREAD))
72 F_SET(&data, DB_DBT_MALLOC);
73 if ((ret = log_get(lp, &last_ckp, &data, DB_CHECKPOINT)) != 0)
74 return (ret == ENOENT ? DB_NOTFOUND : ret);
79 if (F_ISSET(lp, DB_AM_THREAD))
82 if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
84 if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
85 if (F_ISSET(lp, DB_AM_THREAD))
89 if (IS_ZERO_LSN(ckp_lsn))
90 ckp_lsn = ckp_args->ckp_lsn;
92 __db_err(lp->dbenv, "Checkpoint at: [%lu][%lu]",
93 (u_long)last_ckp.file, (u_long)last_ckp.offset);
94 __db_err(lp->dbenv, "Checkpoint LSN: [%lu][%lu]",
95 (u_long)ckp_args->ckp_lsn.file,
96 (u_long)ckp_args->ckp_lsn.offset);
97 __db_err(lp->dbenv, "Previous checkpoint: [%lu][%lu]",
98 (u_long)ckp_args->last_ckp.file,
99 (u_long)ckp_args->last_ckp.offset);
102 next_lsn = ckp_args->last_ckp;
104 } while (!IS_ZERO_LSN(next_lsn) &&
105 log_compare(&last_ckp, &ckp_lsn) > 0);
107 if (F_ISSET(lp, DB_AM_THREAD))
108 __db_free(data.data);
111 * At this point, either, next_lsn is ZERO or ckp_lsn is the
112 * checkpoint lsn and last_ckp is the LSN of the last checkpoint
113 * before ckp_lsn. If the compare in the loop is still true, then
114 * next_lsn must be 0 and we need to roll forward from the
115 * beginning of the log.
117 if (log_compare(&last_ckp, &ckp_lsn) > 0) {
118 if ((ret = log_get(lp, &last_ckp, &data, DB_FIRST)) != 0)
120 if (F_ISSET(lp, DB_AM_THREAD))
121 __db_free(data.data);
126 __db_err(lp->dbenv, "Rolling forward from [%lu][%lu]",
127 (u_long)last_ckp.file, (u_long)last_ckp.offset);
129 return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0);