Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_rec.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_rec.c,v 12.12 2005/10/27 01:03:01 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/log.h"
00022 #include "dbinc/mp.h"
00023 #include "dbinc/hash.h"
00024 
00025 static int __db_pg_free_recover_int __P((DB_ENV *,
00026     __db_pg_freedata_args *, DB *, DB_LSN *, DB_MPOOLFILE *, db_recops, int));
00027 
00028 /*
00029  * PUBLIC: int __db_addrem_recover
00030  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00031  *
00032  * This log message is generated whenever we add or remove a duplicate
00033  * to/from a duplicate page.  On recover, we just do the opposite.
00034  */
00035 int
00036 __db_addrem_recover(dbenv, dbtp, lsnp, op, info)
00037         DB_ENV *dbenv;
00038         DBT *dbtp;
00039         DB_LSN *lsnp;
00040         db_recops op;
00041         void *info;
00042 {
00043         __db_addrem_args *argp;
00044         DB *file_dbp;
00045         DBC *dbc;
00046         DB_MPOOLFILE *mpf;
00047         PAGE *pagep;
00048         u_int32_t change;
00049         int cmp_n, cmp_p, ret;
00050 
00051         pagep = NULL;
00052         COMPQUIET(info, NULL);
00053         REC_PRINT(__db_addrem_print);
00054         REC_INTRO(__db_addrem_read, 1, 1);
00055 
00056         REC_FGET(mpf, argp->pgno, &pagep, done);
00057 
00058         cmp_n = log_compare(lsnp, &LSN(pagep));
00059         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00060         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00061         change = 0;
00062         if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_DUP) ||
00063             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_DUP)) {
00064 
00065                 /* Need to redo an add, or undo a delete. */
00066                 if ((ret = __db_pitem(dbc, pagep, argp->indx, argp->nbytes,
00067                     argp->hdr.size == 0 ? NULL : &argp->hdr,
00068                     argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
00069                         goto out;
00070 
00071                 change = DB_MPOOL_DIRTY;
00072 
00073         } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_DUP) ||
00074             (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_DUP)) {
00075                 /* Need to undo an add, or redo a delete. */
00076                 if ((ret = __db_ditem(dbc,
00077                     pagep, argp->indx, argp->nbytes)) != 0)
00078                         goto out;
00079                 change = DB_MPOOL_DIRTY;
00080         }
00081 
00082         if (change) {
00083                 if (DB_REDO(op))
00084                         LSN(pagep) = *lsnp;
00085                 else
00086                         LSN(pagep) = argp->pagelsn;
00087         }
00088 
00089         if ((ret = __memp_fput(mpf, pagep, change)) != 0)
00090                 goto out;
00091         pagep = NULL;
00092 
00093 done:   *lsnp = argp->prev_lsn;
00094         ret = 0;
00095 
00096 out:    if (pagep != NULL)
00097                 (void)__memp_fput(mpf, pagep, 0);
00098         REC_CLOSE;
00099 }
00100 
00101 /*
00102  * PUBLIC: int __db_big_recover
00103  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00104  */
00105 int
00106 __db_big_recover(dbenv, dbtp, lsnp, op, info)
00107         DB_ENV *dbenv;
00108         DBT *dbtp;
00109         DB_LSN *lsnp;
00110         db_recops op;
00111         void *info;
00112 {
00113         __db_big_args *argp;
00114         DB *file_dbp;
00115         DBC *dbc;
00116         DB_MPOOLFILE *mpf;
00117         PAGE *pagep;
00118         u_int32_t change;
00119         int cmp_n, cmp_p, ret;
00120 
00121         pagep = NULL;
00122         COMPQUIET(info, NULL);
00123         REC_PRINT(__db_big_print);
00124         REC_INTRO(__db_big_read, 1, 0);
00125 
00126         REC_FGET(mpf, argp->pgno, &pagep, ppage);
00127 
00128         /*
00129          * There are three pages we need to check.  The one on which we are
00130          * adding data, the previous one whose next_pointer may have
00131          * been updated, and the next one whose prev_pointer may have
00132          * been updated.
00133          */
00134         cmp_n = log_compare(lsnp, &LSN(pagep));
00135         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00136         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00137         change = 0;
00138         if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) ||
00139             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) {
00140                 /* We are either redo-ing an add, or undoing a delete. */
00141                 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
00142                         argp->next_pgno, 0, P_OVERFLOW);
00143                 OV_LEN(pagep) = argp->dbt.size;
00144                 OV_REF(pagep) = 1;
00145                 memcpy((u_int8_t *)pagep + P_OVERHEAD(file_dbp), argp->dbt.data,
00146                     argp->dbt.size);
00147                 PREV_PGNO(pagep) = argp->prev_pgno;
00148                 change = DB_MPOOL_DIRTY;
00149         } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_BIG) ||
00150             (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) {
00151                 /*
00152                  * We are either undo-ing an add or redo-ing a delete.
00153                  * The page is about to be reclaimed in either case, so
00154                  * there really isn't anything to do here.
00155                  */
00156                 change = DB_MPOOL_DIRTY;
00157         }
00158         if (change)
00159                 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00160 
00161         if ((ret = __memp_fput(mpf, pagep, change)) != 0)
00162                 goto out;
00163         pagep = NULL;
00164 
00165         /*
00166          * We only delete a whole chain of overflow.
00167          * Each page is handled individually
00168          */
00169         if (argp->opcode == DB_REM_BIG)
00170                 goto done;
00171 
00172         /* Now check the previous page. */
00173 ppage:  if (argp->prev_pgno != PGNO_INVALID) {
00174                 change = 0;
00175                 REC_FGET(mpf, argp->prev_pgno, &pagep, npage);
00176 
00177                 cmp_n = log_compare(lsnp, &LSN(pagep));
00178                 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
00179                 CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->prevlsn);
00180 
00181                 if (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) {
00182                         /* Redo add, undo delete. */
00183                         NEXT_PGNO(pagep) = argp->pgno;
00184                         change = DB_MPOOL_DIRTY;
00185                 } else if (cmp_n == 0 &&
00186                     DB_UNDO(op) && argp->opcode == DB_ADD_BIG) {
00187                         /* Redo delete, undo add. */
00188                         NEXT_PGNO(pagep) = argp->next_pgno;
00189                         change = DB_MPOOL_DIRTY;
00190                 }
00191                 if (change)
00192                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
00193                 if ((ret = __memp_fput(mpf, pagep, change)) != 0)
00194                         goto out;
00195         }
00196         pagep = NULL;
00197 
00198         /* Now check the next page.  Can only be set on a delete. */
00199 npage:  if (argp->next_pgno != PGNO_INVALID) {
00200                 change = 0;
00201                 REC_FGET(mpf, argp->next_pgno, &pagep, done);
00202 
00203                 cmp_n = log_compare(lsnp, &LSN(pagep));
00204                 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
00205                 CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->nextlsn);
00206                 if (cmp_p == 0 && DB_REDO(op)) {
00207                         PREV_PGNO(pagep) = PGNO_INVALID;
00208                         change = DB_MPOOL_DIRTY;
00209                 } else if (cmp_n == 0 && DB_UNDO(op)) {
00210                         PREV_PGNO(pagep) = argp->pgno;
00211                         change = DB_MPOOL_DIRTY;
00212                 }
00213                 if (change)
00214                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
00215                 if ((ret = __memp_fput(mpf, pagep, change)) != 0)
00216                         goto out;
00217         }
00218         pagep = NULL;
00219 
00220 done:   *lsnp = argp->prev_lsn;
00221         ret = 0;
00222 
00223 out:    if (pagep != NULL)
00224                 (void)__memp_fput(mpf, pagep, 0);
00225         REC_CLOSE;
00226 }
00227 
00228 /*
00229  * __db_ovref_recover --
00230  *      Recovery function for __db_ovref().
00231  *
00232  * PUBLIC: int __db_ovref_recover
00233  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00234  */
00235 int
00236 __db_ovref_recover(dbenv, dbtp, lsnp, op, info)
00237         DB_ENV *dbenv;
00238         DBT *dbtp;
00239         DB_LSN *lsnp;
00240         db_recops op;
00241         void *info;
00242 {
00243         __db_ovref_args *argp;
00244         DB *file_dbp;
00245         DBC *dbc;
00246         DB_MPOOLFILE *mpf;
00247         PAGE *pagep;
00248         int cmp, modified, ret;
00249 
00250         pagep = NULL;
00251         COMPQUIET(info, NULL);
00252         REC_PRINT(__db_ovref_print);
00253         REC_INTRO(__db_ovref_read, 1, 0);
00254 
00255         REC_FGET(mpf, argp->pgno, &pagep, done);
00256 
00257         modified = 0;
00258         cmp = log_compare(&LSN(pagep), &argp->lsn);
00259         CHECK_LSN(dbenv, op, cmp, &LSN(pagep), &argp->lsn);
00260         if (cmp == 0 && DB_REDO(op)) {
00261                 /* Need to redo update described. */
00262                 OV_REF(pagep) += argp->adjust;
00263 
00264                 pagep->lsn = *lsnp;
00265                 modified = 1;
00266         } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
00267                 /* Need to undo update described. */
00268                 OV_REF(pagep) -= argp->adjust;
00269 
00270                 pagep->lsn = argp->lsn;
00271                 modified = 1;
00272         }
00273         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00274                 goto out;
00275         pagep = NULL;
00276 
00277 done:   *lsnp = argp->prev_lsn;
00278         ret = 0;
00279 
00280 out:    if (pagep != NULL)
00281                 (void)__memp_fput(mpf, pagep, 0);
00282         REC_CLOSE;
00283 }
00284 
00285 /*
00286  * __db_debug_recover --
00287  *      Recovery function for debug.
00288  *
00289  * PUBLIC: int __db_debug_recover __P((DB_ENV *,
00290  * PUBLIC:     DBT *, DB_LSN *, db_recops, void *));
00291  */
00292 int
00293 __db_debug_recover(dbenv, dbtp, lsnp, op, info)
00294         DB_ENV *dbenv;
00295         DBT *dbtp;
00296         DB_LSN *lsnp;
00297         db_recops op;
00298         void *info;
00299 {
00300         __db_debug_args *argp;
00301         int ret;
00302 
00303         COMPQUIET(dbenv, NULL);
00304         COMPQUIET(op, DB_TXN_ABORT);
00305         COMPQUIET(info, NULL);
00306 
00307         REC_PRINT(__db_debug_print);
00308         REC_NOOP_INTRO(__db_debug_read);
00309 
00310         *lsnp = argp->prev_lsn;
00311         ret = 0;
00312 
00313         REC_NOOP_CLOSE;
00314 }
00315 
00316 /*
00317  * __db_noop_recover --
00318  *      Recovery function for noop.
00319  *
00320  * PUBLIC: int __db_noop_recover __P((DB_ENV *,
00321  * PUBLIC:      DBT *, DB_LSN *, db_recops, void *));
00322  */
00323 int
00324 __db_noop_recover(dbenv, dbtp, lsnp, op, info)
00325         DB_ENV *dbenv;
00326         DBT *dbtp;
00327         DB_LSN *lsnp;
00328         db_recops op;
00329         void *info;
00330 {
00331         __db_noop_args *argp;
00332         DB *file_dbp;
00333         DBC *dbc;
00334         DB_MPOOLFILE *mpf;
00335         PAGE *pagep;
00336         u_int32_t change;
00337         int cmp_n, cmp_p, ret;
00338 
00339         pagep = NULL;
00340         COMPQUIET(info, NULL);
00341         REC_PRINT(__db_noop_print);
00342         REC_INTRO(__db_noop_read, 0, 0);
00343 
00344         REC_FGET(mpf, argp->pgno, &pagep, done);
00345 
00346         cmp_n = log_compare(lsnp, &LSN(pagep));
00347         cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
00348         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->prevlsn);
00349         change = 0;
00350         if (cmp_p == 0 && DB_REDO(op)) {
00351                 LSN(pagep) = *lsnp;
00352                 change = DB_MPOOL_DIRTY;
00353         } else if (cmp_n == 0 && DB_UNDO(op)) {
00354                 LSN(pagep) = argp->prevlsn;
00355                 change = DB_MPOOL_DIRTY;
00356         }
00357         ret = __memp_fput(mpf, pagep, change);
00358         pagep = NULL;
00359 
00360 done:   *lsnp = argp->prev_lsn;
00361 out:    if (pagep != NULL)
00362                 (void)__memp_fput(mpf, pagep, 0);
00363         REC_CLOSE;
00364 }
00365 
00366 /*
00367  * __db_pg_alloc_recover --
00368  *      Recovery function for pg_alloc.
00369  *
00370  * PUBLIC: int __db_pg_alloc_recover
00371  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00372  */
00373 int
00374 __db_pg_alloc_recover(dbenv, dbtp, lsnp, op, info)
00375         DB_ENV *dbenv;
00376         DBT *dbtp;
00377         DB_LSN *lsnp;
00378         db_recops op;
00379         void *info;
00380 {
00381         __db_pg_alloc_args *argp;
00382         DB *file_dbp;
00383         DBC *dbc;
00384         DBMETA *meta;
00385         DB_MPOOLFILE *mpf;
00386         PAGE *pagep;
00387         db_pgno_t pgno;
00388         int cmp_n, cmp_p, created, level, meta_modified, modified, ret;
00389 
00390         meta = NULL;
00391         pagep = NULL;
00392         created = meta_modified = modified = 0;
00393         REC_PRINT(__db_pg_alloc_print);
00394         REC_INTRO(__db_pg_alloc_read, 0, 0);
00395 
00396         /*
00397          * Fix up the metadata page.  If we're redoing the operation, we have
00398          * to get the metadata page and update its LSN and its free pointer.
00399          * If we're undoing the operation and the page was ever created, we put
00400          * it on the freelist.
00401          */
00402         pgno = PGNO_BASE_MD;
00403         if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0) {
00404                 /* The metadata page must always exist on redo. */
00405                 if (DB_REDO(op)) {
00406                         ret = __db_pgerr(file_dbp, pgno, ret);
00407                         goto out;
00408                 } else
00409                         goto done;
00410         }
00411         cmp_n = log_compare(lsnp, &LSN(meta));
00412         cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
00413         CHECK_LSN(dbenv, op, cmp_p, &LSN(meta), &argp->meta_lsn);
00414         if (cmp_p == 0 && DB_REDO(op)) {
00415                 /* Need to redo update described. */
00416                 LSN(meta) = *lsnp;
00417                 meta->free = argp->next;
00418                 meta_modified = 1;
00419                 if (argp->pgno > meta->last_pgno)
00420                         meta->last_pgno = argp->pgno;
00421         } else if (cmp_n == 0 && DB_UNDO(op)) {
00422                 /* Need to undo update described. */
00423                 LSN(meta) = argp->meta_lsn;
00424                 /*
00425                  * If the page has a zero LSN then its newly created
00426                  * and will be truncated or go into limbo rather than
00427                  * directly on the free list.
00428                  */
00429                 if (!IS_ZERO_LSN(argp->page_lsn))
00430                         meta->free = argp->pgno;
00431 #ifdef HAVE_FTRUNCATE
00432                 /*
00433                  * With truncate we will restore the file to
00434                  * its original length.  Without truncate
00435                  * the last_pgno never goes backward.
00436                  */
00437                 meta->last_pgno = argp->last_pgno;
00438 #endif
00439                 meta_modified = 1;
00440         }
00441 
00442 #ifdef HAVE_FTRUNCATE
00443         /*
00444          * Check to see if we are keeping a sorted
00445          * freelist, if so put this back in the in
00446          * memory list.  It must be the first element.
00447          */
00448         if (op == DB_TXN_ABORT && !IS_ZERO_LSN(argp->page_lsn)) {
00449                 db_pgno_t *list;
00450                 u_int32_t nelem;
00451 
00452                 if ((ret = __memp_get_freelist(mpf, &nelem, &list)) != 0)
00453                         goto out;
00454                 if (list != NULL) {
00455                         if ((ret =
00456                             __memp_extend_freelist(mpf, nelem + 1, &list)) != 0)
00457                                 goto out;
00458                         if (nelem != 0)
00459                                 memmove(list + 1, list, nelem * sizeof(list));
00460                         *list = argp->pgno;
00461                 }
00462         }
00463 #endif
00464 
00465         /*
00466          * Fix up the allocated page. If the page does not exist
00467          * and we can truncate it then don't create it.
00468          * Otherwise if we're redoing the operation, we have
00469          * to get the page (creating it if it doesn't exist), and update its
00470          * LSN.  If we're undoing the operation, we have to reset the page's
00471          * LSN and put it on the free list, or into limbo..
00472          */
00473         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00474                 /*
00475                  * We have to be able to identify if a page was newly
00476                  * created so we can recover it properly.  We cannot simply
00477                  * look for an empty header, because hash uses a pgin
00478                  * function that will set the header.  Instead, we explicitly
00479                  * try for the page without CREATE and if that fails, then
00480                  * create it.
00481                  */
00482 #ifdef HAVE_FTRUNCATE
00483                 if (DB_UNDO(op))
00484                         goto do_truncate;
00485 #endif
00486                 if ((ret = __memp_fget(
00487                     mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00488                         if (DB_UNDO(op) && ret == ENOSPC)
00489                                 goto do_truncate;
00490                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00491                         goto out;
00492                 }
00493                 created = modified = 1;
00494         }
00495 
00496         /* Fix up the allocated page. */
00497         cmp_n = log_compare(lsnp, &LSN(pagep));
00498         cmp_p = log_compare(&LSN(pagep), &argp->page_lsn);
00499 
00500         /*
00501          * If an initial allocation is aborted and then reallocated during
00502          * an archival restore the log record will have an LSN for the page
00503          * but the page will be empty.
00504          * If we we rolled back this allocation previously during an
00505          * archive restore, the page may have INIT_LSN from the limbo list.
00506          */
00507         if (IS_ZERO_LSN(LSN(pagep)) ||
00508             (IS_ZERO_LSN(argp->page_lsn) && IS_INIT_LSN(LSN(pagep))))
00509                 cmp_p = 0;
00510 
00511         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->page_lsn);
00512         /*
00513          * Another special case we have to handle is if we ended up with a
00514          * page of all 0's which can happen if we abort between allocating a
00515          * page in mpool and initializing it.  In that case, even if we're
00516          * undoing, we need to re-initialize the page.
00517          */
00518         if (DB_REDO(op) && cmp_p == 0) {
00519                 /* Need to redo update described. */
00520                 switch (argp->ptype) {
00521                 case P_LBTREE:
00522                 case P_LRECNO:
00523                 case P_LDUP:
00524                         level = LEAFLEVEL;
00525                         break;
00526                 default:
00527                         level = 0;
00528                         break;
00529                 }
00530                 P_INIT(pagep, file_dbp->pgsize,
00531                     argp->pgno, PGNO_INVALID, PGNO_INVALID, level, argp->ptype);
00532 
00533                 pagep->lsn = *lsnp;
00534                 modified = 1;
00535         } else if (DB_UNDO(op) && (cmp_n == 0 || created)) {
00536                 /*
00537                  * This is where we handle the case of a 0'd page (pagep->pgno
00538                  * is equal to PGNO_INVALID).
00539                  * Undo the allocation, reinitialize the page and
00540                  * link its next pointer to the free list.
00541                  */
00542                 P_INIT(pagep, file_dbp->pgsize,
00543                     argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
00544 
00545                 pagep->lsn = argp->page_lsn;
00546                 modified = 1;
00547         }
00548 
00549 do_truncate:
00550         /*
00551          * If the page was newly created, give it back, if
00552          * possible.  Otherwise put it into limbo.
00553          */
00554         if ((pagep == NULL || IS_ZERO_LSN(LSN(pagep))) &&
00555             IS_ZERO_LSN(argp->page_lsn) && DB_UNDO(op)) {
00556 #ifdef HAVE_FTRUNCATE
00557                 COMPQUIET(info, NULL);
00558                 /* Discard the page. */
00559                 if (pagep != NULL) {
00560                         if ((ret =
00561                              __memp_fput(mpf, pagep, DB_MPOOL_DISCARD)) != 0)
00562                                 goto out;
00563                         pagep = NULL;
00564                         /* Give the page back to the OS. */
00565                         if (meta->last_pgno <= argp->pgno &&
00566                             (ret = __memp_ftruncate(mpf, argp->pgno, 0)) != 0)
00567                                 goto out;
00568                 }
00569 #else
00570                 /* Put the page in limbo.*/
00571                 if ((ret = __db_add_limbo(dbenv,
00572                     info, argp->fileid, argp->pgno, 1)) != 0)
00573                         goto out;
00574                 /* The last_pgno grows if this was a new page. */
00575                 if (argp->pgno > meta->last_pgno) {
00576                         meta->last_pgno = argp->pgno;
00577                         meta_modified = 1;
00578                 }
00579 #endif
00580         }
00581 
00582         if (pagep != NULL &&
00583              (ret = __memp_fput(mpf,
00584              pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00585                 goto out;
00586         pagep = NULL;
00587 
00588         if ((ret = __memp_fput(mpf,
00589             meta, meta_modified ? DB_MPOOL_DIRTY : 0)) != 0)
00590                 goto out;
00591         meta = NULL;
00592 
00593 done:   *lsnp = argp->prev_lsn;
00594         ret = 0;
00595 
00596 out:    if (pagep != NULL)
00597                 (void)__memp_fput(mpf, pagep, 0);
00598         if (meta != NULL)
00599                 (void)__memp_fput(mpf, meta, 0);
00600         if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
00601                 ret = 0;
00602         REC_CLOSE;
00603 }
00604 
00605 /*
00606  * __db_pg_free_recover_int --
00607  */
00608 static int
00609 __db_pg_free_recover_int(dbenv, argp, file_dbp, lsnp, mpf, op, data)
00610         DB_ENV *dbenv;
00611         __db_pg_freedata_args *argp;
00612         DB *file_dbp;
00613         DB_LSN *lsnp;
00614         DB_MPOOLFILE *mpf;
00615         db_recops op;
00616         int data;
00617 {
00618         DBMETA *meta;
00619         DB_LSN copy_lsn;
00620         PAGE *pagep, *prevp;
00621         int cmp_n, cmp_p, is_meta, meta_modified, modified, ret;
00622 
00623         meta = NULL;
00624         pagep = NULL;
00625         prevp = NULL;
00626         meta_modified = modified = 0;
00627 
00628         /*
00629          * Get the "metapage".  This will either be the metapage
00630          * or the previous page in the free list if we are doing
00631          * sorted allocations.  If its a previous page then
00632          * we will not be truncating.
00633          */
00634         is_meta = argp->meta_pgno == PGNO_BASE_MD;
00635 
00636         REC_FGET(mpf, argp->meta_pgno, &meta, check_meta);
00637 
00638         if (argp->meta_pgno != PGNO_BASE_MD)
00639                 prevp = (PAGE *)meta;
00640 
00641         cmp_n = log_compare(lsnp, &LSN(meta));
00642         cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
00643         CHECK_LSN(dbenv, op, cmp_p, &LSN(meta), &argp->meta_lsn);
00644 
00645         /*
00646          * Fix up the metadata page.  If we're redoing or undoing the operation
00647          * we get the page and update its LSN, last and free pointer.
00648          */
00649         if (cmp_p == 0 && DB_REDO(op)) {
00650 #ifdef HAVE_FTRUNCATE
00651                 /*
00652                  * If we are at the end of the file truncate, otherwise
00653                  * put on the free list.
00654                 */
00655                 if (argp->pgno == argp->last_pgno)
00656                         meta->last_pgno = argp->pgno - 1;
00657                 else if (prevp == NULL)
00658                         meta->free = argp->pgno;
00659                 else
00660                         NEXT_PGNO(prevp) = argp->pgno;
00661 #else
00662                 /* Need to redo the deallocation. */
00663                 if (prevp == NULL)
00664                         meta->free = argp->pgno;
00665                 else
00666                         NEXT_PGNO(prevp) = argp->pgno;
00667                 /*
00668                  * If this was a compensating transaction and
00669                  * we are a replica, then we never executed the
00670                  * original allocation which incremented meta->free.
00671                  */
00672                 if (prevp == NULL && meta->last_pgno < meta->free)
00673                         meta->last_pgno = meta->free;
00674 #endif
00675                 LSN(meta) = *lsnp;
00676                 meta_modified = 1;
00677         } else if (cmp_n == 0 && DB_UNDO(op)) {
00678                 /* Need to undo the deallocation. */
00679                 if (prevp == NULL)
00680                         meta->free = argp->next;
00681                 else
00682                         NEXT_PGNO(prevp) = argp->next;
00683                 LSN(meta) = argp->meta_lsn;
00684                 if (prevp == NULL && meta->last_pgno < argp->pgno)
00685                         meta->last_pgno = argp->pgno;
00686                 meta_modified = 1;
00687         }
00688 
00689 check_meta:
00690         if (ret != 0 && is_meta) {
00691                 /* The metadata page must always exist. */
00692                 ret = __db_pgerr(file_dbp, argp->meta_pgno, ret);
00693                 goto out;
00694         }
00695 
00696         /*
00697          * Get the freed page.  If we support truncate then don't
00698          * create the page if we are going to free it.  If we're
00699          * redoing the operation we get the page and explicitly discard
00700          * its contents, then update its LSN.  If we're undoing the
00701          * operation, we get the page and restore its header.
00702          * If we don't support truncate, then we must create the page
00703          * and roll it back.
00704          */
00705 #ifdef HAVE_FTRUNCATE
00706         if (DB_REDO(op) || (is_meta && meta->last_pgno < argp->pgno)) {
00707                 if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00708                         if (ret == DB_PAGE_NOTFOUND)
00709                                 goto done;
00710                         goto out;
00711                 }
00712         } else
00713 #endif
00714         if ((ret =
00715             __memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
00716                 goto out;
00717 
00718         (void)__ua_memcpy(&copy_lsn, &LSN(argp->header.data), sizeof(DB_LSN));
00719         cmp_n = IS_ZERO_LSN(LSN(pagep)) ? 0 : log_compare(lsnp, &LSN(pagep));
00720         cmp_p = log_compare(&LSN(pagep), &copy_lsn);
00721 
00722 #ifdef HAVE_FTRUNCATE
00723         /*
00724          * This page got extended by a later allocation,
00725          * but its allocation was not in the scope of this
00726          * recovery pass.
00727          */
00728         if (IS_ZERO_LSN(LSN(pagep)))
00729                 cmp_p = 0;
00730 #endif
00731 
00732         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &copy_lsn);
00733         if (DB_REDO(op) &&
00734             (cmp_p == 0 ||
00735             (IS_ZERO_LSN(copy_lsn) &&
00736             log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) {
00737                 /* Need to redo the deallocation. */
00738 #ifdef HAVE_FTRUNCATE
00739                 /*
00740                  * The page can be truncated if it was truncated at runtime
00741                  * and the current metapage reflects the truncation.
00742                  */
00743                 if (is_meta && meta->last_pgno <= argp->pgno &&
00744                     argp->last_pgno <= argp->pgno) {
00745                         if ((ret =
00746                             __memp_fput(mpf, pagep, DB_MPOOL_DISCARD)) != 0)
00747                                 goto out;
00748                         pagep = NULL;
00749                         if ((ret = __memp_ftruncate(mpf, argp->pgno, 0)) != 0)
00750                                 goto out;
00751                 } else if (argp->last_pgno == argp->pgno) {
00752                         /* The page was truncated at runtime, zero it out. */
00753                         P_INIT(pagep, 0, PGNO_INVALID,
00754                             PGNO_INVALID, PGNO_INVALID, 0, P_INVALID);
00755                         ZERO_LSN(pagep->lsn);
00756                         modified = 1;
00757                 } else
00758 #endif
00759                 {
00760                         P_INIT(pagep, file_dbp->pgsize,
00761                             argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
00762                         pagep->lsn = *lsnp;
00763 
00764                         modified = 1;
00765                 }
00766         } else if (cmp_n == 0 && DB_UNDO(op)) {
00767                 /* Need to reallocate the page. */
00768                 memcpy(pagep, argp->header.data, argp->header.size);
00769                 if (data)
00770                         memcpy((u_int8_t*)pagep + HOFFSET(pagep),
00771                              argp->data.data, argp->data.size);
00772 
00773                 modified = 1;
00774         }
00775         if (pagep != NULL &&
00776             (ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00777                 goto out;
00778 
00779         pagep = NULL;
00780 #ifdef HAVE_FTRUNCATE
00781         /*
00782          * If we are keeping an in memory free list remove this
00783          * element from the list.
00784          */
00785         if (op == DB_TXN_ABORT && argp->pgno != argp->last_pgno) {
00786                 db_pgno_t *lp;
00787                 u_int32_t nelem, pos;
00788 
00789                 if ((ret = __memp_get_freelist(mpf, &nelem, &lp)) != 0)
00790                         goto out;
00791                 if (lp != NULL) {
00792                         pos = 0;
00793                         if (!is_meta && nelem != 0) {
00794                                 __db_freelist_pos(argp->pgno, lp, nelem, &pos);
00795 
00796                                 DB_ASSERT(argp->pgno == lp[pos]);
00797                                 DB_ASSERT(argp->meta_pgno == lp[pos - 1]);
00798                         }
00799 
00800                         if (nelem != 0 && pos != nelem)
00801                                 memmove(&lp[pos], &lp[pos + 1],
00802                                     (nelem - pos) * sizeof(*lp));
00803 
00804                         /* Shrink the list */
00805                         if ((ret =
00806                             __memp_extend_freelist(mpf, nelem - 1, &lp)) != 0)
00807                                 goto out;
00808                 }
00809         }
00810 done:
00811 #endif
00812         if (meta != NULL && (ret = __memp_fput(mpf,
00813              meta, meta_modified ? DB_MPOOL_DIRTY : 0)) != 0)
00814                 goto out;
00815         meta = NULL;
00816 
00817         ret = 0;
00818 
00819 out:    if (pagep != NULL)
00820                 (void)__memp_fput(mpf, pagep, 0);
00821         if (meta != NULL)
00822                 (void)__memp_fput(mpf, meta, 0);
00823 
00824         return (ret);
00825 }
00826 
00827 /*
00828  * __db_pg_free_recover --
00829  *      Recovery function for pg_free.
00830  *
00831  * PUBLIC: int __db_pg_free_recover
00832  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00833  */
00834 int
00835 __db_pg_free_recover(dbenv, dbtp, lsnp, op, info)
00836         DB_ENV *dbenv;
00837         DBT *dbtp;
00838         DB_LSN *lsnp;
00839         db_recops op;
00840         void *info;
00841 {
00842         DB *file_dbp;
00843         DBC *dbc;
00844         DB_MPOOLFILE *mpf;
00845         __db_pg_free_args *argp;
00846         int ret;
00847 
00848         COMPQUIET(info, NULL);
00849         REC_PRINT(__db_pg_free_print);
00850         REC_INTRO(__db_pg_free_read, 1, 0);
00851 
00852         ret = __db_pg_free_recover_int(dbenv,
00853              (__db_pg_freedata_args *)argp, file_dbp, lsnp, mpf, op, 0);
00854 
00855 done:   *lsnp = argp->prev_lsn;
00856 out:
00857         REC_CLOSE;
00858 }
00859 
00860 /*
00861  * __db_pg_new_recover --
00862  *      A new page from the file was put on the free list.
00863  * This record is only generated during a LIMBO_COMPENSATE.
00864  *
00865  * PUBLIC: int __db_pg_new_recover
00866  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00867  */
00868 int
00869 __db_pg_new_recover(dbenv, dbtp, lsnp, op, info)
00870         DB_ENV *dbenv;
00871         DBT *dbtp;
00872         DB_LSN *lsnp;
00873         db_recops op;
00874         void *info;
00875 {
00876 #ifndef HAVE_FTRUNCATE
00877         DB *file_dbp;
00878         DBC *dbc;
00879         DB_MPOOLFILE *mpf;
00880         __db_pg_free_args *argp;
00881         int ret;
00882 
00883         REC_PRINT(__db_pg_free_print);
00884         REC_INTRO(__db_pg_free_read, 1, 0);
00885         COMPQUIET(op, DB_TXN_ABORT);
00886 
00887         if ((ret =
00888             __db_add_limbo(dbenv, info, argp->fileid, argp->pgno, 1)) == 0)
00889                 *lsnp = argp->prev_lsn;
00890 
00891 done:
00892 out:
00893         REC_CLOSE;
00894 #else
00895         COMPQUIET(dbenv, NULL);
00896         COMPQUIET(dbtp, NULL);
00897         COMPQUIET(lsnp, NULL);
00898         COMPQUIET(op, DB_TXN_PRINT);
00899         COMPQUIET(info, NULL);
00900         return (0);
00901 #endif
00902 }
00903 
00904 /*
00905  * __db_pg_freedata_recover --
00906  *      Recovery function for pg_freedata.
00907  *
00908  * PUBLIC: int __db_pg_freedata_recover
00909  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00910  */
00911 int
00912 __db_pg_freedata_recover(dbenv, dbtp, lsnp, op, info)
00913         DB_ENV *dbenv;
00914         DBT *dbtp;
00915         DB_LSN *lsnp;
00916         db_recops op;
00917         void *info;
00918 {
00919         DB *file_dbp;
00920         DBC *dbc;
00921         DB_MPOOLFILE *mpf;
00922         __db_pg_freedata_args *argp;
00923         int ret;
00924 
00925         COMPQUIET(info, NULL);
00926         REC_PRINT(__db_pg_freedata_print);
00927         REC_INTRO(__db_pg_freedata_read, 1, 0);
00928 
00929         ret = __db_pg_free_recover_int(dbenv, argp, file_dbp, lsnp, mpf, op, 1);
00930 
00931 done:   *lsnp = argp->prev_lsn;
00932 out:
00933         REC_CLOSE;
00934 }
00935 
00936 /*
00937  * __db_cksum_recover --
00938  *      Recovery function for checksum failure log record.
00939  *
00940  * PUBLIC: int __db_cksum_recover __P((DB_ENV *,
00941  * PUBLIC:      DBT *, DB_LSN *, db_recops, void *));
00942  */
00943 int
00944 __db_cksum_recover(dbenv, dbtp, lsnp, op, info)
00945         DB_ENV *dbenv;
00946         DBT *dbtp;
00947         DB_LSN *lsnp;
00948         db_recops op;
00949         void *info;
00950 {
00951         __db_cksum_args *argp;
00952 
00953         int ret;
00954 
00955         COMPQUIET(info, NULL);
00956         COMPQUIET(lsnp, NULL);
00957         COMPQUIET(op, DB_TXN_ABORT);
00958 
00959         REC_PRINT(__db_cksum_print);
00960 
00961         if ((ret = __db_cksum_read(dbenv, dbtp->data, &argp)) != 0)
00962                 return (ret);
00963 
00964         /*
00965          * We had a checksum failure -- the only option is to run catastrophic
00966          * recovery.
00967          */
00968         if (F_ISSET(dbenv, DB_ENV_FATAL))
00969                 ret = 0;
00970         else {
00971                 __db_err(dbenv,
00972                     "Checksum failure requires catastrophic recovery");
00973                 ret = __db_panic(dbenv, DB_RUNRECOVERY);
00974         }
00975 
00976         __os_free(dbenv, argp);
00977         return (ret);
00978 }
00979 
00980 /*
00981  * __db_pg_prepare_recover --
00982  *      Recovery function for pg_prepare.
00983  *
00984  * PUBLIC: int __db_pg_prepare_recover
00985  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00986  */
00987 int
00988 __db_pg_prepare_recover(dbenv, dbtp, lsnp, op, info)
00989         DB_ENV *dbenv;
00990         DBT *dbtp;
00991         DB_LSN *lsnp;
00992         db_recops op;
00993         void *info;
00994 {
00995 #ifndef HAVE_FTRUNCATE
00996         __db_pg_prepare_args *argp;
00997         DB *file_dbp;
00998         DBC *dbc;
00999         DB_MPOOLFILE *mpf;
01000         PAGE *pagep;
01001         int ret, t_ret;
01002 
01003         REC_PRINT(__db_pg_prepare_print);
01004         REC_INTRO(__db_pg_prepare_read, 1, 0);
01005 
01006         mpf = file_dbp->mpf;
01007 
01008         /*
01009          * If this made it into the limbo list at prepare time then
01010          * it was a new free page allocated by an aborted subtransaction.
01011          * Only that subtransaction could have toched the page.
01012          * All other pages in the free list at this point are
01013          * either of the same nature or were put there by this subtransactions
01014          * other subtransactions that followed this one.  If
01015          * they were put there by this subtransaction the log records
01016          * of the following allocations will reflect that.
01017          * Note that only one transaction could have had the
01018          * metapage locked at the point of the crash.
01019          * All this is to say that we can P_INIT this page without
01020          * loosing other pages on the free list because they
01021          * will be linked in by records earlier in the log for
01022          * this transaction which we will roll back.
01023          */
01024         if (op == DB_TXN_ABORT) {
01025                 if ((ret = __memp_fget(
01026                     mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
01027                         goto out;
01028                 P_INIT(pagep, file_dbp->pgsize,
01029                     argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, P_INVALID);
01030                 ZERO_LSN(pagep->lsn);
01031                 ret = __db_add_limbo(dbenv, info, argp->fileid, argp->pgno, 1);
01032                 if ((t_ret =
01033                     __memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
01034                         ret = t_ret;
01035         }
01036 
01037 done:   if (ret == 0)
01038                 *lsnp = argp->prev_lsn;
01039 out:    REC_CLOSE;
01040 #else
01041         COMPQUIET(dbenv, NULL);
01042         COMPQUIET(dbtp, NULL);
01043         COMPQUIET(lsnp, NULL);
01044         COMPQUIET(op, DB_TXN_PRINT);
01045         COMPQUIET(info, NULL);
01046         return (0);
01047 #endif
01048 
01049 }
01050 
01051 /*
01052  * __db_pg_init_recover --
01053  *      Recovery function to reinit pages for truncate.
01054  *
01055  * PUBLIC: int __db_pg_init_recover
01056  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01057  */
01058 int
01059 __db_pg_init_recover(dbenv, dbtp, lsnp, op, info)
01060         DB_ENV *dbenv;
01061         DBT *dbtp;
01062         DB_LSN *lsnp;
01063         db_recops op;
01064         void *info;
01065 {
01066         __db_pg_init_args *argp;
01067         DB *file_dbp;
01068         DBC *dbc;
01069         DB_LSN copy_lsn;
01070         DB_MPOOLFILE *mpf;
01071         PAGE *pagep;
01072         int cmp_n, cmp_p, modified, ret, type;
01073 
01074         COMPQUIET(info, NULL);
01075         REC_PRINT(__db_pg_init_print);
01076         REC_INTRO(__db_pg_init_read, 1, 0);
01077 
01078         mpf = file_dbp->mpf;
01079         REC_FGET(mpf, argp->pgno, &pagep, done);
01080 
01081         modified = 0;
01082         (void)__ua_memcpy(&copy_lsn, &LSN(argp->header.data), sizeof(DB_LSN));
01083         cmp_n = log_compare(lsnp, &LSN(pagep));
01084         cmp_p = log_compare(&LSN(pagep), &copy_lsn);
01085         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &copy_lsn);
01086 
01087         if (cmp_p == 0 && DB_REDO(op)) {
01088                 if (TYPE(pagep) == P_HASH)
01089                         type = P_HASH;
01090                 else
01091                         type = file_dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE;
01092                 P_INIT(pagep, file_dbp->pgsize, PGNO(pagep), PGNO_INVALID,
01093                     PGNO_INVALID, TYPE(pagep) == P_HASH ? 0 : 1, type);
01094                 pagep->lsn = *lsnp;
01095                 modified = 1;
01096         } else if (cmp_n == 0 && DB_UNDO(op)) {
01097                 /* Put the data back on the page. */
01098                 memcpy(pagep, argp->header.data, argp->header.size);
01099                 if (argp->data.size > 0)
01100                         memcpy((u_int8_t*)pagep + HOFFSET(pagep),
01101                              argp->data.data, argp->data.size);
01102 
01103                 modified = 1;
01104         }
01105         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01106                 goto out;
01107 
01108 done:   *lsnp = argp->prev_lsn;
01109 out:
01110         REC_CLOSE;
01111 }
01112 
01113 /*
01114  * __db_pg_sort_recover --
01115  *      Recovery function for pg_sort.
01116  *
01117  * PUBLIC: int __db_pg_sort_recover
01118  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01119  */
01120 int
01121 __db_pg_sort_recover(dbenv, dbtp, lsnp, op, info)
01122         DB_ENV *dbenv;
01123         DBT *dbtp;
01124         DB_LSN *lsnp;
01125         db_recops op;
01126         void *info;
01127 {
01128 #ifdef HAVE_FTRUNCATE
01129         __db_pg_sort_args *argp;
01130         DB *file_dbp;
01131         DBC *dbc;
01132         DBMETA *meta;
01133         DB_MPOOLFILE *mpf;
01134         PAGE *pagep;
01135         db_pgno_t pgno, *list;
01136         u_int32_t felem, nelem;
01137         struct pglist *pglist, *lp;
01138         int modified, ret;
01139 
01140         COMPQUIET(info, NULL);
01141 
01142         REC_PRINT(__db_pg_sort_print);
01143         REC_INTRO(__db_pg_sort_read, 1, 1);
01144 
01145         modified = 0;
01146 
01147         pglist = (struct pglist *) argp->list.data;
01148         nelem = argp->list.size / sizeof(struct pglist);
01149         if (DB_REDO(op)) {
01150                 pgno = argp->last_pgno;
01151                 if ((ret = __db_pg_truncate(mpf,
01152                     pglist, NULL, &nelem, &pgno, lsnp, 1)) != 0)
01153                         goto out;
01154 
01155                 if (argp->last_free != PGNO_INVALID) {
01156                         if ((ret = __memp_fget(mpf,
01157                              &argp->last_free, 0, &meta)) == 0) {
01158                                 if (log_compare(&LSN(meta),
01159                                      &argp->last_lsn) == 0) {
01160                                         NEXT_PGNO(meta) = PGNO_INVALID;
01161                                         LSN(meta) = *lsnp;
01162                                         modified = 1;
01163                                 }
01164                                 if ((ret = __memp_fput(mpf,
01165                                      meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01166                                         goto out;
01167                                 meta = NULL;
01168                                 modified = 0;
01169                         } else if (ret != DB_PAGE_NOTFOUND)
01170                                 goto out;
01171                 }
01172                 if ((ret = __memp_fget(mpf, &argp->meta, 0, &meta)) != 0)
01173                         goto out;
01174                 if (log_compare(&LSN(meta), &argp->meta_lsn) == 0) {
01175                         if (argp->last_free == PGNO_INVALID) {
01176                                 if (nelem == 0)
01177                                         meta->free = PGNO_INVALID;
01178                                 else
01179                                         meta->free = pglist->pgno;
01180                         }
01181                         meta->last_pgno = pgno;
01182                         LSN(meta) = *lsnp;
01183                         modified = 1;
01184                 }
01185         } else {
01186                 /* Put the free list back in its original order. */
01187                 for (lp = pglist; lp < &pglist[nelem]; lp++) {
01188                         if ((ret = __memp_fget(mpf,
01189                              &lp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
01190                                 goto out;
01191                         if (IS_ZERO_LSN(LSN(pagep)) ||
01192                              log_compare(&LSN(pagep), lsnp) == 0) {
01193                                 if (lp == &pglist[nelem - 1])
01194                                         pgno = PGNO_INVALID;
01195                                 else
01196                                         pgno = lp[1].pgno;
01197 
01198                                 P_INIT(pagep, file_dbp->pgsize,
01199                                     lp->pgno, PGNO_INVALID, pgno, 0, P_INVALID);
01200                                 LSN(pagep) = lp->lsn;
01201                                 modified = 1;
01202                         }
01203                         if ((ret = __memp_fput(mpf,
01204                              pagep, modified ? DB_MPOOL_DIRTY: 0)) != 0)
01205                                 goto out;
01206                 }
01207                 if (argp->last_free != PGNO_INVALID) {
01208                         if ((ret = __memp_fget(mpf,
01209                              &argp->last_free, 0, &meta)) == 0) {
01210                                 if (log_compare(&LSN(meta), lsnp) == 0) {
01211                                         NEXT_PGNO(meta) = pglist->pgno;
01212                                         LSN(meta) = argp->last_lsn;
01213                                         modified = 1;
01214                                 }
01215                                 if ((ret = __memp_fput(mpf,
01216                                      meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01217                                         goto out;
01218                         } else if (ret != DB_PAGE_NOTFOUND)
01219                                 goto out;
01220                         modified = 0;
01221                         meta = NULL;
01222                 }
01223                 if ((ret = __memp_fget(mpf, &argp->meta, 0, &meta)) != 0)
01224                         goto out;
01225                 if (log_compare(&LSN(meta), lsnp) == 0) {
01226                         meta->last_pgno = argp->last_pgno;
01227                         if (argp->last_pgno == PGNO_INVALID)
01228                                 meta->free = pglist->pgno;
01229                         LSN(meta) = argp->meta_lsn;
01230                         modified = 1;
01231                 }
01232         }
01233         if (op == DB_TXN_ABORT) {
01234                 if ((ret = __memp_get_freelist(mpf, &felem, &list)) != 0)
01235                         goto out;
01236                 if (list != NULL) {
01237                         DB_ASSERT(felem == 0 ||
01238                             argp->last_free == list[felem - 1]);
01239                         if ((ret = __memp_extend_freelist(
01240                             mpf, felem + nelem, &list)) != 0)
01241                                 goto out;
01242                         for (lp = pglist; lp < &pglist[nelem]; lp++)
01243                                 list[felem++] = lp->pgno;
01244                 }
01245         }
01246 
01247         if ((ret = __memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01248                 goto out;
01249 
01250 done:   *lsnp = argp->prev_lsn;
01251         ret = 0;
01252 
01253 out:    REC_CLOSE;
01254 #else
01255         /*
01256          * If HAVE_FTRUNCATE is not defined, we'll never see pg_sort records
01257          * to recover.
01258          */
01259         COMPQUIET(dbenv, NULL);
01260         COMPQUIET(dbtp, NULL);
01261         COMPQUIET(lsnp, NULL);
01262         COMPQUIET(op,  DB_TXN_ABORT);
01263         COMPQUIET(info, NULL);
01264         return (EINVAL);
01265 #endif
01266 }

Generated on Sun Dec 25 12:14:21 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2