db_rec.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: db__rec_8c-source.html,v 1.1 2008/06/08 10:18:14 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "db_page.h"
00022 #include "log.h"
00023 #include "hash.h"
00024 
00025 /*
00026  * PUBLIC: int CDB___db_addrem_recover
00027  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00028  *
00029  * This log message is generated whenever we add or remove a duplicate
00030  * to/from a duplicate page.  On recover, we just do the opposite.
00031  */
00032 int
00033 CDB___db_addrem_recover(dbenv, dbtp, lsnp, op, info)
00034         DB_ENV *dbenv;
00035         DBT *dbtp;
00036         DB_LSN *lsnp;
00037         db_recops op;
00038         void *info;
00039 {
00040         __db_addrem_args *argp;
00041         DB *file_dbp;
00042         DBC *dbc;
00043         DB_MPOOLFILE *mpf;
00044         PAGE *pagep;
00045         u_int32_t change;
00046         int cmp_n, cmp_p, ret;
00047 
00048         COMPQUIET(info, NULL);
00049         REC_PRINT(CDB___db_addrem_print);
00050         REC_INTRO(CDB___db_addrem_read, 1);
00051 
00052         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00053                 if (DB_UNDO(op)) {
00054                         /*
00055                          * We are undoing and the page doesn't exist.  That
00056                          * is equivalent to having a pagelsn of 0, so we
00057                          * would not have to undo anything.  In this case,
00058                          * don't bother creating a page.
00059                          */
00060                         goto done;
00061                 } else
00062                         if ((ret = CDB_memp_fget(mpf,
00063                             &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
00064                                 goto out;
00065         }
00066 
00067         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00068         cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00069         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00070         change = 0;
00071         if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_DUP) ||
00072             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_DUP)) {
00073 
00074                 /* Need to redo an add, or undo a delete. */
00075                 if ((ret = CDB___db_pitem(dbc, pagep, argp->indx, argp->nbytes,
00076                     argp->hdr.size == 0 ? NULL : &argp->hdr,
00077                     argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
00078                         goto out;
00079 
00080                 change = DB_MPOOL_DIRTY;
00081 
00082         } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_DUP) ||
00083             (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_DUP)) {
00084                 /* Need to undo an add, or redo a delete. */
00085                 if ((ret = CDB___db_ditem(dbc,
00086                     pagep, argp->indx, argp->nbytes)) != 0)
00087                         goto out;
00088                 change = DB_MPOOL_DIRTY;
00089         }
00090 
00091         if (change) {
00092                 if (DB_REDO(op))
00093                         LSN(pagep) = *lsnp;
00094                 else
00095                         LSN(pagep) = argp->pagelsn;
00096         }
00097 
00098         if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0)
00099                 goto out;
00100 
00101 done:   *lsnp = argp->prev_lsn;
00102         ret = 0;
00103 
00104 out:    REC_CLOSE;
00105 }
00106 
00107 /*
00108  * PUBLIC: int CDB___db_big_recover
00109  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00110  */
00111 int
00112 CDB___db_big_recover(dbenv, dbtp, lsnp, op, info)
00113         DB_ENV *dbenv;
00114         DBT *dbtp;
00115         DB_LSN *lsnp;
00116         db_recops op;
00117         void *info;
00118 {
00119         __db_big_args *argp;
00120         DB *file_dbp;
00121         DBC *dbc;
00122         DB_MPOOLFILE *mpf;
00123         PAGE *pagep;
00124         u_int32_t change;
00125         int cmp_n, cmp_p, ret;
00126 
00127         COMPQUIET(info, NULL);
00128         REC_PRINT(CDB___db_big_print);
00129         REC_INTRO(CDB___db_big_read, 1);
00130 
00131         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00132                 if (DB_UNDO(op)) {
00133                         /*
00134                          * We are undoing and the page doesn't exist.  That
00135                          * is equivalent to having a pagelsn of 0, so we
00136                          * would not have to undo anything.  In this case,
00137                          * don't bother creating a page.
00138                          */
00139                         ret = 0;
00140                         goto ppage;
00141                 } else
00142                         if ((ret = CDB_memp_fget(mpf,
00143                             &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
00144                                 goto out;
00145         }
00146 
00147         /*
00148          * There are three pages we need to check.  The one on which we are
00149          * adding data, the previous one whose next_pointer may have
00150          * been updated, and the next one whose prev_pointer may have
00151          * been updated.
00152          */
00153         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00154         cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00155         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00156         change = 0;
00157         if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) ||
00158             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) {
00159                 /* We are either redo-ing an add, or undoing a delete. */
00160                 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
00161                         argp->next_pgno, 0, P_OVERFLOW, TAGS(argp));
00162                 OV_LEN(pagep) = argp->dbt.size;
00163                 OV_REF(pagep) = 1;
00164                 memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
00165                     argp->dbt.size);
00166                 PREV_PGNO(pagep) = argp->prev_pgno;
00167                 change = DB_MPOOL_DIRTY;
00168         } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_BIG) ||
00169             (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) {
00170                 /*
00171                  * We are either undo-ing an add or redo-ing a delete.
00172                  * The page is about to be reclaimed in either case, so
00173                  * there really isn't anything to do here.
00174                  */
00175                 change = DB_MPOOL_DIRTY;
00176         }
00177         if (change)
00178                 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00179 
00180         if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0)
00181                 goto out;
00182 
00183         /* Now check the previous page. */
00184 ppage:  if (argp->prev_pgno != PGNO_INVALID) {
00185                 change = 0;
00186                 if ((ret = CDB_memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
00187                         if (DB_UNDO(op)) {
00188                                 /*
00189                                  * We are undoing and the page doesn't exist.
00190                                  * That is equivalent to having a pagelsn of 0,
00191                                  * so we would not have to undo anything.  In
00192                                  * this case, don't bother creating a page.
00193                                  */
00194                                 *lsnp = argp->prev_lsn;
00195                                 ret = 0;
00196                                 goto npage;
00197                         } else
00198                                 if ((ret = CDB_memp_fget(mpf, &argp->prev_pgno,
00199                                     DB_MPOOL_CREATE, &pagep)) != 0)
00200                                         goto out;
00201                 }
00202 
00203                 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00204                 cmp_p = CDB_log_compare(&LSN(pagep), &argp->prevlsn);
00205                 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
00206 
00207                 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) ||
00208                     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) {
00209                         /* Redo add, undo delete. */
00210                         NEXT_PGNO(pagep) = argp->pgno;
00211                         change = DB_MPOOL_DIRTY;
00212                 } else if ((cmp_n == 0 &&
00213                     DB_UNDO(op) && argp->opcode == DB_ADD_BIG) ||
00214                     (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) {
00215                         /* Redo delete, undo add. */
00216                         NEXT_PGNO(pagep) = argp->next_pgno;
00217                         change = DB_MPOOL_DIRTY;
00218                 }
00219                 if (change)
00220                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
00221                 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0)
00222                         goto out;
00223         }
00224 
00225         /* Now check the next page.  Can only be set on a delete. */
00226 npage:  if (argp->next_pgno != PGNO_INVALID) {
00227                 change = 0;
00228                 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
00229                         if (DB_UNDO(op)) {
00230                                 /*
00231                                  * We are undoing and the page doesn't exist.
00232                                  * That is equivalent to having a pagelsn of 0,
00233                                  * so we would not have to undo anything.  In
00234                                  * this case, don't bother creating a page.
00235                                  */
00236                                 goto done;
00237                         } else
00238                                 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno,
00239                                     DB_MPOOL_CREATE, &pagep)) != 0)
00240                                         goto out;
00241                 }
00242 
00243                 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00244                 cmp_p = CDB_log_compare(&LSN(pagep), &argp->nextlsn);
00245                 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
00246                 if (cmp_p == 0 && DB_REDO(op)) {
00247                         PREV_PGNO(pagep) = PGNO_INVALID;
00248                         change = DB_MPOOL_DIRTY;
00249                 } else if (cmp_n == 0 && DB_UNDO(op)) {
00250                         PREV_PGNO(pagep) = argp->pgno;
00251                         change = DB_MPOOL_DIRTY;
00252                 }
00253                 if (change)
00254                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
00255                 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0)
00256                         goto out;
00257         }
00258 
00259 done:   *lsnp = argp->prev_lsn;
00260         ret = 0;
00261 
00262 out:    REC_CLOSE;
00263 }
00264 
00265 /*
00266  * CDB___db_ovref_recover --
00267  *      Recovery function for CDB___db_ovref().
00268  *
00269  * PUBLIC: int CDB___db_ovref_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00270  */
00271 int
00272 CDB___db_ovref_recover(dbenv, dbtp, lsnp, op, info)
00273         DB_ENV *dbenv;
00274         DBT *dbtp;
00275         DB_LSN *lsnp;
00276         db_recops op;
00277         void *info;
00278 {
00279         __db_ovref_args *argp;
00280         DB *file_dbp;
00281         DBC *dbc;
00282         DB_MPOOLFILE *mpf;
00283         PAGE *pagep;
00284         int cmp, modified, ret;
00285 
00286         COMPQUIET(info, NULL);
00287         REC_PRINT(CDB___db_ovref_print);
00288         REC_INTRO(CDB___db_ovref_read, 1);
00289 
00290         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00291                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00292                 goto out;
00293         }
00294 
00295         modified = 0;
00296         cmp = CDB_log_compare(&LSN(pagep), &argp->lsn);
00297         CHECK_LSN(op, cmp, &LSN(pagep), &argp->lsn);
00298         if (cmp == 0 && DB_REDO(op)) {
00299                 /* Need to redo update described. */
00300                 OV_REF(pagep) += argp->adjust;
00301 
00302                 pagep->lsn = *lsnp;
00303                 modified = 1;
00304         } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
00305                 /* Need to undo update described. */
00306                 OV_REF(pagep) -= argp->adjust;
00307 
00308                 pagep->lsn = argp->lsn;
00309                 modified = 1;
00310         }
00311         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00312                 goto out;
00313 
00314 done:   *lsnp = argp->prev_lsn;
00315         ret = 0;
00316 
00317 out:    REC_CLOSE;
00318 }
00319 
00320 /*
00321  * CDB___db_relink_recover --
00322  *      Recovery function for relink.
00323  *
00324  * PUBLIC: int CDB___db_relink_recover
00325  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00326  */
00327 int
00328 CDB___db_relink_recover(dbenv, dbtp, lsnp, op, info)
00329         DB_ENV *dbenv;
00330         DBT *dbtp;
00331         DB_LSN *lsnp;
00332         db_recops op;
00333         void *info;
00334 {
00335         __db_relink_args *argp;
00336         DB *file_dbp;
00337         DBC *dbc;
00338         DB_MPOOLFILE *mpf;
00339         PAGE *pagep;
00340         int cmp_n, cmp_p, modified, ret;
00341 
00342         COMPQUIET(info, NULL);
00343         REC_PRINT(CDB___db_relink_print);
00344         REC_INTRO(CDB___db_relink_read, 1);
00345 
00346         /*
00347          * There are up to three pages we need to check -- the page, and the
00348          * previous and next pages, if they existed.  For a page add operation,
00349          * the current page is the result of a split and is being recovered
00350          * elsewhere, so all we need do is recover the next page.
00351          */
00352         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00353                 if (DB_REDO(op)) {
00354                         (void)CDB___db_pgerr(file_dbp, argp->pgno);
00355                         goto out;
00356                 }
00357                 goto next2;
00358         }
00359         modified = 0;
00360         if (argp->opcode == DB_ADD_PAGE)
00361                 goto next1;
00362 
00363         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00364         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00365         if (cmp_p == 0 && DB_REDO(op)) {
00366                 /* Redo the relink. */
00367                 pagep->lsn = *lsnp;
00368                 modified = 1;
00369         } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
00370                 /* Undo the relink. */
00371                 pagep->next_pgno = argp->next;
00372                 pagep->prev_pgno = argp->prev;
00373 
00374                 pagep->lsn = argp->lsn;
00375                 modified = 1;
00376         }
00377 next1:  if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00378                 goto out;
00379 
00380 next2:  if ((ret = CDB_memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
00381                 if (DB_REDO(op)) {
00382                         (void)CDB___db_pgerr(file_dbp, argp->next);
00383                         goto out;
00384                 }
00385                 goto prev;
00386         }
00387         modified = 0;
00388         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00389         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn_next);
00390         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_next);
00391         if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && DB_REDO(op)) ||
00392             (argp->opcode == DB_ADD_PAGE && cmp_n == 0 && DB_UNDO(op))) {
00393                 /* Redo the remove or undo the add. */
00394                 pagep->prev_pgno = argp->prev;
00395 
00396                 modified = 1;
00397         } else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && DB_UNDO(op)) ||
00398             (argp->opcode == DB_ADD_PAGE && cmp_p == 0 && DB_REDO(op))) {
00399                 /* Undo the remove or redo the add. */
00400                 pagep->prev_pgno = argp->pgno;
00401 
00402                 modified = 1;
00403         }
00404         if (modified == 1) {
00405                 if (DB_UNDO(op))
00406                         pagep->lsn = argp->lsn_next;
00407                 else
00408                         pagep->lsn = *lsnp;
00409         }
00410         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00411                 goto out;
00412         if (argp->opcode == DB_ADD_PAGE)
00413                 goto done;
00414 
00415 prev:   if ((ret = CDB_memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
00416                 if (DB_REDO(op)) {
00417                         (void)CDB___db_pgerr(file_dbp, argp->prev);
00418                         goto out;
00419                 }
00420                 goto done;
00421         }
00422         modified = 0;
00423         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn_prev);
00424         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_prev);
00425         if (cmp_p == 0 && DB_REDO(op)) {
00426                 /* Redo the relink. */
00427                 pagep->next_pgno = argp->next;
00428 
00429                 modified = 1;
00430         } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
00431                 /* Undo the relink. */
00432                 pagep->next_pgno = argp->pgno;
00433 
00434                 modified = 1;
00435         }
00436         if (modified == 1) {
00437                 if (DB_UNDO(op))
00438                         pagep->lsn = argp->lsn_prev;
00439                 else
00440                         pagep->lsn = *lsnp;
00441         }
00442         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00443                 goto out;
00444 
00445 done:   *lsnp = argp->prev_lsn;
00446         ret = 0;
00447 
00448 out:    REC_CLOSE;
00449 }
00450 
00451 /*
00452  * CDB___db_debug_recover --
00453  *      Recovery function for debug.
00454  *
00455  * PUBLIC: int CDB___db_debug_recover __P((DB_ENV *,
00456  * PUBLIC:     DBT *, DB_LSN *, db_recops, void *));
00457  */
00458 int
00459 CDB___db_debug_recover(dbenv, dbtp, lsnp, op, info)
00460         DB_ENV *dbenv;
00461         DBT *dbtp;
00462         DB_LSN *lsnp;
00463         db_recops op;
00464         void *info;
00465 {
00466         __db_debug_args *argp;
00467         int ret;
00468 
00469         COMPQUIET(op, 0);
00470         COMPQUIET(dbenv, NULL);
00471         COMPQUIET(info, NULL);
00472 
00473         REC_PRINT(CDB___db_debug_print);
00474         REC_NOOP_INTRO(CDB___db_debug_read);
00475 
00476         *lsnp = argp->prev_lsn;
00477         ret = 0;
00478 
00479         REC_NOOP_CLOSE;
00480 }
00481 
00482 /*
00483  * CDB___db_noop_recover --
00484  *      Recovery function for noop.
00485  *
00486  * PUBLIC: int CDB___db_noop_recover __P((DB_ENV *,
00487  * PUBLIC:      DBT *, DB_LSN *, db_recops, void *));
00488  */
00489 int
00490 CDB___db_noop_recover(dbenv, dbtp, lsnp, op, info)
00491         DB_ENV *dbenv;
00492         DBT *dbtp;
00493         DB_LSN *lsnp;
00494         db_recops op;
00495         void *info;
00496 {
00497         __db_noop_args *argp;
00498         DB *file_dbp;
00499         DBC *dbc;
00500         DB_MPOOLFILE *mpf;
00501         PAGE *pagep;
00502         u_int32_t change;
00503         int cmp_n, cmp_p, ret;
00504 
00505         COMPQUIET(info, NULL);
00506         REC_PRINT(CDB___db_noop_print);
00507         REC_INTRO(CDB___db_noop_read, 0);
00508 
00509         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
00510                 goto out;
00511 
00512         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00513         cmp_p = CDB_log_compare(&LSN(pagep), &argp->prevlsn);
00514         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
00515         change = 0;
00516         if (cmp_p == 0 && DB_REDO(op)) {
00517                 LSN(pagep) = *lsnp;
00518                 change = DB_MPOOL_DIRTY;
00519         } else if (cmp_n == 0 && DB_UNDO(op)) {
00520                 LSN(pagep) = argp->prevlsn;
00521                 change = DB_MPOOL_DIRTY;
00522         }
00523         ret = CDB_memp_fput(mpf, pagep, change);
00524 
00525 done:   *lsnp = argp->prev_lsn;
00526 out:    REC_CLOSE;
00527 }

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