xref: /illumos-gate/usr/src/cmd/sendmail/db/log/log_findckp.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1*7c478bd9Sstevel@tonic-gate /*-
2*7c478bd9Sstevel@tonic-gate  * See the file LICENSE for redistribution information.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, 1997, 1998
5*7c478bd9Sstevel@tonic-gate  *	Sleepycat Software.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  */
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #include "config.h"
9*7c478bd9Sstevel@tonic-gate 
10*7c478bd9Sstevel@tonic-gate #ifndef lint
11*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)log_findckp.c	10.17 (Sleepycat) 9/17/98";
12*7c478bd9Sstevel@tonic-gate #endif /* not lint */
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
15*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <errno.h>
18*7c478bd9Sstevel@tonic-gate #include <string.h>
19*7c478bd9Sstevel@tonic-gate #endif
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate #include "db_int.h"
22*7c478bd9Sstevel@tonic-gate #include "shqueue.h"
23*7c478bd9Sstevel@tonic-gate #include "log.h"
24*7c478bd9Sstevel@tonic-gate #include "txn.h"
25*7c478bd9Sstevel@tonic-gate #include "common_ext.h"
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * __log_findckp --
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * Looks for the most recent checkpoint that occurs before the most recent
31*7c478bd9Sstevel@tonic-gate  * checkpoint LSN, subject to the constraint that there must be at least two
32*7c478bd9Sstevel@tonic-gate  * checkpoints.  The reason you need two checkpoints is that you might have
33*7c478bd9Sstevel@tonic-gate  * crashed during the most recent one and may not have a copy of all the
34*7c478bd9Sstevel@tonic-gate  * open files.  This is the point from which recovery can start and the
35*7c478bd9Sstevel@tonic-gate  * point up to which archival/truncation can take place.  Checkpoints in
36*7c478bd9Sstevel@tonic-gate  * the log look like:
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  * -------------------------------------------------------------------
39*7c478bd9Sstevel@tonic-gate  *  | ckp A, ckplsn 100 |  .... record .... | ckp B, ckplsn 600 | ...
40*7c478bd9Sstevel@tonic-gate  * -------------------------------------------------------------------
41*7c478bd9Sstevel@tonic-gate  *         LSN 500                                 LSN 1000
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  * If we read what log returns from using the DB_CKP parameter to logput,
44*7c478bd9Sstevel@tonic-gate  * we'll get the record at LSN 1000.  The checkpoint LSN there is 600.
45*7c478bd9Sstevel@tonic-gate  * Now we have to scan backwards looking for a checkpoint before LSN 600.
46*7c478bd9Sstevel@tonic-gate  * We find one at 500.  This means that we can truncate the log before
47*7c478bd9Sstevel@tonic-gate  * 500 or run recovery beginning at 500.
48*7c478bd9Sstevel@tonic-gate  *
49*7c478bd9Sstevel@tonic-gate  * Returns 0 if we find a suitable checkpoint or we retrieved the
50*7c478bd9Sstevel@tonic-gate  * first record in the log from which to start.
51*7c478bd9Sstevel@tonic-gate  * Returns DB_NOTFOUND if there are no log records.
52*7c478bd9Sstevel@tonic-gate  * Returns errno on error.
53*7c478bd9Sstevel@tonic-gate  *
54*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __log_findckp __P((DB_LOG *, DB_LSN *));
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate int
__log_findckp(lp,lsnp)57*7c478bd9Sstevel@tonic-gate __log_findckp(lp, lsnp)
58*7c478bd9Sstevel@tonic-gate 	DB_LOG *lp;
59*7c478bd9Sstevel@tonic-gate 	DB_LSN *lsnp;
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	DBT data;
62*7c478bd9Sstevel@tonic-gate 	DB_LSN ckp_lsn, final_ckp, last_ckp, next_lsn;
63*7c478bd9Sstevel@tonic-gate 	__txn_ckp_args *ckp_args;
64*7c478bd9Sstevel@tonic-gate 	int ret, verbose;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	verbose = lp->dbenv != NULL && lp->dbenv->db_verbose != 0;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	/*
69*7c478bd9Sstevel@tonic-gate 	 * Need to find the appropriate point from which to begin
70*7c478bd9Sstevel@tonic-gate 	 * recovery.
71*7c478bd9Sstevel@tonic-gate 	 */
72*7c478bd9Sstevel@tonic-gate 	memset(&data, 0, sizeof(data));
73*7c478bd9Sstevel@tonic-gate 	if (F_ISSET(lp, DB_AM_THREAD))
74*7c478bd9Sstevel@tonic-gate 		F_SET(&data, DB_DBT_MALLOC);
75*7c478bd9Sstevel@tonic-gate 	ZERO_LSN(ckp_lsn);
76*7c478bd9Sstevel@tonic-gate 	if ((ret = log_get(lp, &last_ckp, &data, DB_CHECKPOINT)) != 0)
77*7c478bd9Sstevel@tonic-gate 		if (ret == ENOENT)
78*7c478bd9Sstevel@tonic-gate 			goto get_first;
79*7c478bd9Sstevel@tonic-gate 		else
80*7c478bd9Sstevel@tonic-gate 			return (ret);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	final_ckp = last_ckp;
83*7c478bd9Sstevel@tonic-gate 	next_lsn = last_ckp;
84*7c478bd9Sstevel@tonic-gate 	do {
85*7c478bd9Sstevel@tonic-gate 		if (F_ISSET(lp, DB_AM_THREAD))
86*7c478bd9Sstevel@tonic-gate 			__os_free(data.data, data.size);
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 		if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
89*7c478bd9Sstevel@tonic-gate 			return (ret);
90*7c478bd9Sstevel@tonic-gate 		if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
91*7c478bd9Sstevel@tonic-gate 			if (F_ISSET(lp, DB_AM_THREAD))
92*7c478bd9Sstevel@tonic-gate 				__os_free(data.data, data.size);
93*7c478bd9Sstevel@tonic-gate 			return (ret);
94*7c478bd9Sstevel@tonic-gate 		}
95*7c478bd9Sstevel@tonic-gate 		if (IS_ZERO_LSN(ckp_lsn))
96*7c478bd9Sstevel@tonic-gate 			ckp_lsn = ckp_args->ckp_lsn;
97*7c478bd9Sstevel@tonic-gate 		if (verbose) {
98*7c478bd9Sstevel@tonic-gate 			__db_err(lp->dbenv, "Checkpoint at: [%lu][%lu]",
99*7c478bd9Sstevel@tonic-gate 			    (u_long)last_ckp.file, (u_long)last_ckp.offset);
100*7c478bd9Sstevel@tonic-gate 			__db_err(lp->dbenv, "Checkpoint LSN: [%lu][%lu]",
101*7c478bd9Sstevel@tonic-gate 			    (u_long)ckp_args->ckp_lsn.file,
102*7c478bd9Sstevel@tonic-gate 			    (u_long)ckp_args->ckp_lsn.offset);
103*7c478bd9Sstevel@tonic-gate 			__db_err(lp->dbenv, "Previous checkpoint: [%lu][%lu]",
104*7c478bd9Sstevel@tonic-gate 			    (u_long)ckp_args->last_ckp.file,
105*7c478bd9Sstevel@tonic-gate 			    (u_long)ckp_args->last_ckp.offset);
106*7c478bd9Sstevel@tonic-gate 		}
107*7c478bd9Sstevel@tonic-gate 		last_ckp = next_lsn;
108*7c478bd9Sstevel@tonic-gate 		next_lsn = ckp_args->last_ckp;
109*7c478bd9Sstevel@tonic-gate 		__os_free(ckp_args, sizeof(*ckp_args));
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 		/*
112*7c478bd9Sstevel@tonic-gate 		 * Keep looping until either you 1) run out of checkpoints,
113*7c478bd9Sstevel@tonic-gate 		 * 2) you've found a checkpoint before the most recent
114*7c478bd9Sstevel@tonic-gate 		 * checkpoint's LSN and you have at least 2 checkpoints.
115*7c478bd9Sstevel@tonic-gate 		 */
116*7c478bd9Sstevel@tonic-gate 	} while (!IS_ZERO_LSN(next_lsn) &&
117*7c478bd9Sstevel@tonic-gate 	    (log_compare(&last_ckp, &ckp_lsn) > 0 ||
118*7c478bd9Sstevel@tonic-gate 	    log_compare(&final_ckp, &last_ckp) == 0));
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	if (F_ISSET(lp, DB_AM_THREAD))
121*7c478bd9Sstevel@tonic-gate 		__os_free(data.data, data.size);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	/*
124*7c478bd9Sstevel@tonic-gate 	 * At this point, either, next_lsn is ZERO or ckp_lsn is the
125*7c478bd9Sstevel@tonic-gate 	 * checkpoint lsn and last_ckp is the LSN of the last checkpoint
126*7c478bd9Sstevel@tonic-gate 	 * before ckp_lsn.  If the compare in the loop is still true, then
127*7c478bd9Sstevel@tonic-gate 	 * next_lsn must be 0 and we need to roll forward from the
128*7c478bd9Sstevel@tonic-gate 	 * beginning of the log.
129*7c478bd9Sstevel@tonic-gate 	 */
130*7c478bd9Sstevel@tonic-gate 	if (log_compare(&last_ckp, &ckp_lsn) > 0 ||
131*7c478bd9Sstevel@tonic-gate 	    log_compare(&final_ckp, &last_ckp) == 0) {
132*7c478bd9Sstevel@tonic-gate get_first:	if ((ret = log_get(lp, &last_ckp, &data, DB_FIRST)) != 0)
133*7c478bd9Sstevel@tonic-gate 			return (ret);
134*7c478bd9Sstevel@tonic-gate 		if (F_ISSET(lp, DB_AM_THREAD))
135*7c478bd9Sstevel@tonic-gate 			__os_free(data.data, data.size);
136*7c478bd9Sstevel@tonic-gate 	}
137*7c478bd9Sstevel@tonic-gate 	*lsnp = last_ckp;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0);
140*7c478bd9Sstevel@tonic-gate }
141