log_findckp.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: log__findckp_8c-source.html,v 1.1 2008/06/08 10:20:23 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <errno.h>
00018 #include <string.h>
00019 #endif
00020 
00021 #include "db_int.h"
00022 #include "log.h"
00023 #include "txn.h"
00024 
00025 /*
00026  * CDB___log_findckp --
00027  *
00028  * Looks for the most recent checkpoint that occurs before the most recent
00029  * checkpoint LSN, subject to the constraint that there must be at least two
00030  * checkpoints.  The reason you need two checkpoints is that you might have
00031  * crashed during the most recent one and may not have a copy of all the
00032  * open files.  This is the point from which recovery can start and the
00033  * point up to which archival/truncation can take place.  Checkpoints in
00034  * the log look like:
00035  *
00036  * -------------------------------------------------------------------
00037  *  | ckp A, ckplsn 100 |  .... record .... | ckp B, ckplsn 600 | ...
00038  * -------------------------------------------------------------------
00039  *         LSN 500                                 LSN 1000
00040  *
00041  * If we read what log returns from using the DB_CKP parameter to logput,
00042  * we'll get the record at LSN 1000.  The checkpoint LSN there is 600.
00043  * Now we have to scan backwards looking for a checkpoint before LSN 600.
00044  * We find one at 500.  This means that we can truncate the log before
00045  * 500 or run recovery beginning at 500.
00046  *
00047  * Returns 0 if we find a suitable checkpoint or we retrieved the first
00048  * record in the log from which to start.  Returns DB_NOTFOUND if there
00049  * are no log records, errno on error.
00050  *
00051  * PUBLIC: int CDB___log_findckp __P((DB_ENV *, DB_LSN *));
00052  */
00053 int
00054 CDB___log_findckp(dbenv, lsnp)
00055         DB_ENV *dbenv;
00056         DB_LSN *lsnp;
00057 {
00058         DBT data;
00059         DB_LSN ckp_lsn, final_ckp, last_ckp, next_lsn;
00060         __txn_ckp_args *ckp_args;
00061         int ret;
00062 
00063         /*
00064          * Need to find the appropriate point from which to begin
00065          * recovery.
00066          */
00067         memset(&data, 0, sizeof(data));
00068         if (F_ISSET(dbenv, DB_ENV_THREAD))
00069                 F_SET(&data, DB_DBT_MALLOC);
00070         ZERO_LSN(ckp_lsn);
00071         if ((ret = CDB_log_get(dbenv, &last_ckp, &data, DB_CHECKPOINT)) != 0) {
00072                 if (ret == ENOENT)
00073                         goto get_first;
00074                 else
00075                         return (ret);
00076         }
00077         final_ckp = last_ckp;
00078 
00079         next_lsn = last_ckp;
00080         do {
00081                 if (F_ISSET(dbenv, DB_ENV_THREAD))
00082                         CDB___os_free(data.data, data.size);
00083 
00084                 if ((ret = CDB_log_get(dbenv, &next_lsn, &data, DB_SET)) != 0)
00085                         return (ret);
00086                 if ((ret = CDB___txn_ckp_read(dbenv, data.data, &ckp_args)) != 0) {
00087                         if (F_ISSET(dbenv, DB_ENV_THREAD))
00088                                 CDB___os_free(data.data, data.size);
00089                         return (ret);
00090                 }
00091                 if (IS_ZERO_LSN(ckp_lsn))
00092                         ckp_lsn = ckp_args->ckp_lsn;
00093                 if (FLD_ISSET(dbenv->verbose, DB_VERB_CHKPOINT)) {
00094                         CDB___db_err(dbenv, "Checkpoint at: [%lu][%lu]",
00095                             (u_long)last_ckp.file, (u_long)last_ckp.offset);
00096                         CDB___db_err(dbenv, "Checkpoint LSN: [%lu][%lu]",
00097                             (u_long)ckp_args->ckp_lsn.file,
00098                             (u_long)ckp_args->ckp_lsn.offset);
00099                         CDB___db_err(dbenv, "Previous checkpoint: [%lu][%lu]",
00100                             (u_long)ckp_args->last_ckp.file,
00101                             (u_long)ckp_args->last_ckp.offset);
00102                 }
00103                 last_ckp = next_lsn;
00104                 next_lsn = ckp_args->last_ckp;
00105                 CDB___os_free(ckp_args, sizeof(*ckp_args));
00106 
00107                 /*
00108                  * Keep looping until either you 1) run out of checkpoints,
00109                  * 2) you've found a checkpoint before the most recent
00110                  * checkpoint's LSN and you have at least 2 checkpoints.
00111                  */
00112         } while (!IS_ZERO_LSN(next_lsn) &&
00113             (CDB_log_compare(&last_ckp, &ckp_lsn) > 0 ||
00114             CDB_log_compare(&final_ckp, &last_ckp) == 0));
00115 
00116         if (F_ISSET(dbenv, DB_ENV_THREAD))
00117                 CDB___os_free(data.data, data.size);
00118 
00119         /*
00120          * At this point, either, next_lsn is ZERO or ckp_lsn is the
00121          * checkpoint lsn and last_ckp is the LSN of the last checkpoint
00122          * before ckp_lsn.  If the compare in the loop is still true, then
00123          * next_lsn must be 0 and we need to roll forward from the
00124          * beginning of the log.
00125          */
00126         if (CDB_log_compare(&last_ckp, &ckp_lsn) >= 0 ||
00127             CDB_log_compare(&final_ckp, &last_ckp) == 0) {
00128 get_first:      if ((ret = CDB_log_get(dbenv, &last_ckp, &data, DB_FIRST)) != 0)
00129                         return (ret);
00130                 if (F_ISSET(dbenv, DB_ENV_THREAD))
00131                         CDB___os_free(data.data, data.size);
00132         }
00133         *lsnp = last_ckp;
00134 
00135         return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0);
00136 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5