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 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