Update.
[glibc.git] / db2 / log / log_findckp.c
blob1f717b49e787826fd4183f816c8ff51187e9949b
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)log_findckp.c 10.15 (Sleepycat) 4/26/98";
12 #endif /* not lint */
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
17 #include <errno.h>
18 #include <string.h>
19 #endif
21 #include "db_int.h"
22 #include "shqueue.h"
23 #include "log.h"
24 #include "txn.h"
25 #include "common_ext.h"
28 * __log_findckp --
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
33 * the log look like:
35 * -------------------------------------------------------------------
36 * | ckp A, ckplsn 100 | .... record .... | ckp B, ckplsn 600 | ...
37 * -------------------------------------------------------------------
38 * LSN 500 LSN 1000
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 *));
53 int
54 __log_findckp(lp, lsnp)
55 DB_LOG *lp;
56 DB_LSN *lsnp;
58 DBT data;
59 DB_LSN ckp_lsn, last_ckp, next_lsn;
60 __txn_ckp_args *ckp_args;
61 int ret, verbose;
63 verbose = lp->dbenv != NULL && lp->dbenv->db_verbose != 0;
66 * Need to find the appropriate point from which to begin
67 * recovery.
69 memset(&data, 0, sizeof(data));
70 if (F_ISSET(lp, DB_AM_THREAD))
71 F_SET(&data, DB_DBT_MALLOC);
72 ZERO_LSN(ckp_lsn);
73 if ((ret = log_get(lp, &last_ckp, &data, DB_CHECKPOINT)) != 0) {
74 if (ret == ENOENT)
75 goto get_first;
76 else
77 return (ret);
80 next_lsn = last_ckp;
81 do {
82 if (F_ISSET(lp, DB_AM_THREAD))
83 __db_free(data.data);
85 if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
86 return (ret);
87 if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
88 if (F_ISSET(lp, DB_AM_THREAD))
89 __db_free(data.data);
90 return (ret);
92 if (IS_ZERO_LSN(ckp_lsn))
93 ckp_lsn = ckp_args->ckp_lsn;
94 if (verbose) {
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);
104 last_ckp = next_lsn;
105 next_lsn = ckp_args->last_ckp;
106 __db_free(ckp_args);
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)
122 return (ret);
123 if (F_ISSET(lp, DB_AM_THREAD))
124 __db_free(data.data);
126 *lsnp = last_ckp;
128 return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0);