Update from db-2.3.12.
[kopensolaris-gnu/glibc.git] / db2 / log / log_findckp.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
5  *      Sleepycat Software.  All rights reserved.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)log_findckp.c 10.12 (Sleepycat) 10/25/97";
12 #endif /* not lint */
13
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #endif
21
22 #include "db_int.h"
23 #include "shqueue.h"
24 #include "log.h"
25 #include "txn.h"
26 #include "common_ext.h"
27
28 /*
29  * __log_findckp --
30  *
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
34  * the log look like:
35  *
36  * -------------------------------------------------------------------
37  *  | ckp A, ckplsn 100 |  .... record .... | ckp B, ckplsn 600 | ...
38  * -------------------------------------------------------------------
39  *         LSN 500                                 LSN 1000
40  *
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.
46  *
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.
51  *
52  * PUBLIC: int __log_findckp __P((DB_LOG *, DB_LSN *));
53  */
54 int
55 __log_findckp(lp, lsnp)
56         DB_LOG *lp;
57         DB_LSN *lsnp;
58 {
59         DBT data;
60         DB_LSN ckp_lsn, last_ckp, next_lsn;
61         __txn_ckp_args *ckp_args;
62         int ret, verbose;
63
64         verbose = lp->dbenv != NULL && lp->dbenv->db_verbose != 0;
65
66         /*
67          * Need to find the appropriate point from which to begin
68          * recovery.
69          */
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);
75         ZERO_LSN(ckp_lsn);
76
77         next_lsn = last_ckp;
78         do {
79                 if (F_ISSET(lp, DB_AM_THREAD))
80                         __db_free(data.data);
81
82                 if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
83                         return (ret);
84                 if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
85                         if (F_ISSET(lp, DB_AM_THREAD))
86                                 __db_free(data.data);
87                         return (ret);
88                 }
89                 if (IS_ZERO_LSN(ckp_lsn))
90                         ckp_lsn = ckp_args->ckp_lsn;
91                 if (verbose) {
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);
100                 }
101                 last_ckp = next_lsn;
102                 next_lsn = ckp_args->last_ckp;
103                 __db_free(ckp_args);
104         } while (!IS_ZERO_LSN(next_lsn) &&
105             log_compare(&last_ckp, &ckp_lsn) > 0);
106
107         if (F_ISSET(lp, DB_AM_THREAD))
108                 __db_free(data.data);
109
110         /*
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.
116          */
117         if (log_compare(&last_ckp, &ckp_lsn) > 0) {
118                 if ((ret = log_get(lp, &last_ckp, &data, DB_FIRST)) != 0)
119                         return (ret);
120                 if (F_ISSET(lp, DB_AM_THREAD))
121                         __db_free(data.data);
122         }
123         *lsnp = last_ckp;
124
125         if (verbose)
126                 __db_err(lp->dbenv, "Rolling forward from [%lu][%lu]",
127                         (u_long)last_ckp.file, (u_long)last_ckp.offset);
128
129         return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0);
130 }