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

bt_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: bt_rec.c,v 12.11 2005/10/20 18:57: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/btree.h"
00022 #include "dbinc/lock.h"
00023 #include "dbinc/log.h"
00024 #include "dbinc/mp.h"
00025 
00026 #define IS_BTREE_PAGE(pagep)                                            \
00027         (TYPE(pagep) == P_IBTREE ||                                     \
00028          TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP)
00029 
00030 /*
00031  * __bam_split_recover --
00032  *      Recovery function for split.
00033  *
00034  * PUBLIC: int __bam_split_recover
00035  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00036  */
00037 int
00038 __bam_split_recover(dbenv, dbtp, lsnp, op, info)
00039         DB_ENV *dbenv;
00040         DBT *dbtp;
00041         DB_LSN *lsnp;
00042         db_recops op;
00043         void *info;
00044 {
00045         __bam_split_args *argp;
00046         DB *file_dbp;
00047         DBC *dbc;
00048         DB_MPOOLFILE *mpf;
00049         PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
00050         db_pgno_t pgno, root_pgno;
00051         u_int32_t ptype;
00052         int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret;
00053 
00054         COMPQUIET(info, NULL);
00055         REC_PRINT(__bam_split_print);
00056 
00057         mpf = NULL;
00058         _lp = lp = np = pp = _rp = rp = NULL;
00059         sp = NULL;
00060 
00061         REC_INTRO(__bam_split_read, 1, 0);
00062 
00063         /*
00064          * There are two kinds of splits that we have to recover from.  The
00065          * first is a root-page split, where the root page is split from a
00066          * leaf page into an internal page and two new leaf pages are created.
00067          * The second is where a page is split into two pages, and a new key
00068          * is inserted into the parent page.
00069          *
00070          * DBTs are not aligned in log records, so we need to copy the page
00071          * so that we can access fields within it throughout this routine.
00072          * Although we could hardcode the unaligned copies in this routine,
00073          * we will be calling into regular btree functions with this page,
00074          * so it's got to be aligned.  Copying it into allocated memory is
00075          * the only way to guarantee this.
00076          */
00077         if ((ret = __os_malloc(dbenv, argp->pg.size, &sp)) != 0)
00078                 goto out;
00079         memcpy(sp, argp->pg.data, argp->pg.size);
00080 
00081         pgno = PGNO(sp);
00082         root_pgno = argp->root_pgno;
00083         rootsplit = root_pgno != PGNO_INVALID;
00084         REC_FGET(mpf, argp->left, &lp, right);
00085 right:  REC_FGET(mpf, argp->right, &rp, redo);
00086 
00087 redo:   if (DB_REDO(op)) {
00088                 l_update = r_update = p_update = 0;
00089                 /*
00090                  * Decide if we need to resplit the page.
00091                  *
00092                  * If this is a root split, then the root has to exist unless
00093                  * we have truncated it due to a future deallocation.
00094                  */
00095                 if (rootsplit) {
00096                         REC_FGET(mpf, root_pgno, &pp, do_left);
00097                         cmp =
00098                             log_compare(&LSN(pp), &LSN(argp->pg.data));
00099                         CHECK_LSN(dbenv, op,
00100                             cmp, &LSN(pp), &LSN(argp->pg.data));
00101                         p_update = cmp  == 0;
00102                 }
00103 
00104 do_left:        if (lp != NULL) {
00105                         cmp = log_compare(&LSN(lp), &argp->llsn);
00106                         CHECK_LSN(dbenv, op, cmp, &LSN(lp), &argp->llsn);
00107                         if (cmp == 0)
00108                                 l_update = 1;
00109                 }
00110 
00111                 if (rp != NULL) {
00112                         cmp = log_compare(&LSN(rp), &argp->rlsn);
00113                         CHECK_LSN(dbenv, op, cmp, &LSN(rp), &argp->rlsn);
00114                         if (cmp == 0)
00115                                 r_update = 1;
00116                 }
00117 
00118                 if (!p_update && !l_update && !r_update)
00119                         goto check_next;
00120 
00121                 /* Allocate and initialize new left/right child pages. */
00122                 if ((ret = __os_malloc(dbenv, file_dbp->pgsize, &_lp)) != 0 ||
00123                     (ret = __os_malloc(dbenv, file_dbp->pgsize, &_rp)) != 0)
00124                         goto out;
00125                 if (rootsplit) {
00126                         P_INIT(_lp, file_dbp->pgsize, argp->left,
00127                             PGNO_INVALID,
00128                             ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
00129                             LEVEL(sp), TYPE(sp));
00130                         P_INIT(_rp, file_dbp->pgsize, argp->right,
00131                             ISINTERNAL(sp) ?  PGNO_INVALID : argp->left,
00132                             PGNO_INVALID, LEVEL(sp), TYPE(sp));
00133                 } else {
00134                         P_INIT(_lp, file_dbp->pgsize, PGNO(sp),
00135                             ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp),
00136                             ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
00137                             LEVEL(sp), TYPE(sp));
00138                         P_INIT(_rp, file_dbp->pgsize, argp->right,
00139                             ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno,
00140                             ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp),
00141                             LEVEL(sp), TYPE(sp));
00142                 }
00143 
00144                 /* Split the page. */
00145                 if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 ||
00146                     (ret = __bam_copy(file_dbp, sp, _rp, argp->indx,
00147                     NUM_ENT(sp))) != 0)
00148                         goto out;
00149 
00150                 if (l_update) {
00151                         memcpy(lp, _lp, file_dbp->pgsize);
00152                         lp->lsn = *lsnp;
00153                         if ((ret = __memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
00154                                 goto out;
00155                         lp = NULL;
00156                 }
00157 
00158                 if (r_update) {
00159                         memcpy(rp, _rp, file_dbp->pgsize);
00160                         rp->lsn = *lsnp;
00161                         if ((ret = __memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
00162                                 goto out;
00163                         rp = NULL;
00164                 }
00165 
00166                 /*
00167                  * If the parent page is wrong, update it.  This is of interest
00168                  * only if it was a root split, since root splits create parent
00169                  * pages.  All other splits modify a parent page, but those are
00170                  * separately logged and recovered.
00171                  */
00172                 if (rootsplit && p_update) {
00173                         if (IS_BTREE_PAGE(sp)) {
00174                                 ptype = P_IBTREE;
00175                                 rc = argp->opflags & SPL_NRECS ? 1 : 0;
00176                         } else {
00177                                 ptype = P_IRECNO;
00178                                 rc = 1;
00179                         }
00180 
00181                         P_INIT(pp, file_dbp->pgsize, root_pgno,
00182                             PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype);
00183                         RE_NREC_SET(pp, rc ? __bam_total(file_dbp, _lp) +
00184                             __bam_total(file_dbp, _rp) : 0);
00185 
00186                         pp->lsn = *lsnp;
00187                         if ((ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
00188                                 goto out;
00189                         pp = NULL;
00190                 }
00191 
00192 check_next:     /*
00193                  * Finally, redo the next-page link if necessary.  This is of
00194                  * interest only if it wasn't a root split -- inserting a new
00195                  * page in the tree requires that any following page have its
00196                  * previous-page pointer updated to our new page.  The next
00197                  * page must exist because we're redoing the operation.
00198                  */
00199                 if (!rootsplit && argp->npgno != PGNO_INVALID) {
00200                         if ((ret =
00201                             __memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
00202                                 if (ret != DB_PAGE_NOTFOUND
00203 #ifndef HAVE_FTRUNCATE
00204                                     || DB_REDO(op)
00205 #endif
00206                                     ) {
00207                                         ret = __db_pgerr(
00208                                             file_dbp, argp->npgno, ret);
00209                                         goto out;
00210                                 } else
00211                                         goto done;
00212                         }
00213                         cmp = log_compare(&LSN(np), &argp->nlsn);
00214                         CHECK_LSN(dbenv, op, cmp, &LSN(np), &argp->nlsn);
00215                         if (cmp == 0) {
00216                                 PREV_PGNO(np) = argp->right;
00217                                 np->lsn = *lsnp;
00218                                 if ((ret =
00219                                     __memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0)
00220                                         goto out;
00221                                 np = NULL;
00222                         }
00223                 }
00224         } else {
00225                 /*
00226                  * If the split page is wrong, replace its contents with the
00227                  * logged page contents.  If the page doesn't exist, it means
00228                  * that the create of the page never happened, nor did any of
00229                  * the adds onto the page that caused the split, and there's
00230                  * really no undo-ing to be done.
00231                  */
00232                 if ((ret = __memp_fget(mpf, &pgno, 0, &pp)) != 0) {
00233                         pp = NULL;
00234                         goto lrundo;
00235                 }
00236                 if (log_compare(lsnp, &LSN(pp)) == 0) {
00237                         memcpy(pp, argp->pg.data, argp->pg.size);
00238                         if ((ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
00239                                 goto out;
00240                         pp = NULL;
00241                 }
00242 
00243                 /*
00244                  * If it's a root split and the left child ever existed, update
00245                  * its LSN.  (If it's not a root split, we've updated the left
00246                  * page already -- it's the same as the split page.) If the
00247                  * right child ever existed, root split or not, update its LSN.
00248                  * The undo of the page allocation(s) will restore them to the
00249                  * free list.
00250                  */
00251 lrundo:         if ((rootsplit && lp != NULL) || rp != NULL) {
00252                         if (rootsplit && lp != NULL &&
00253                             log_compare(lsnp, &LSN(lp)) == 0) {
00254                                 lp->lsn = argp->llsn;
00255                                 if ((ret =
00256                                     __memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
00257                                         goto out;
00258                                 lp = NULL;
00259                         }
00260                         if (rp != NULL &&
00261                             log_compare(lsnp, &LSN(rp)) == 0) {
00262                                 rp->lsn = argp->rlsn;
00263                                 if ((ret =
00264                                     __memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
00265                                         goto out;
00266                                 rp = NULL;
00267                         }
00268                 }
00269 
00270                 /*
00271                  * Finally, undo the next-page link if necessary.  This is of
00272                  * interest only if it wasn't a root split -- inserting a new
00273                  * page in the tree requires that any following page have its
00274                  * previous-page pointer updated to our new page.  Since it's
00275                  * possible that the next-page never existed, we ignore it as
00276                  * if there's nothing to undo.
00277                  */
00278                 if (!rootsplit && argp->npgno != PGNO_INVALID) {
00279                         if ((ret =
00280                             __memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
00281                                 np = NULL;
00282                                 goto done;
00283                         }
00284                         if (log_compare(lsnp, &LSN(np)) == 0) {
00285                                 PREV_PGNO(np) = argp->left;
00286                                 np->lsn = argp->nlsn;
00287                                 if (__memp_fput(mpf, np, DB_MPOOL_DIRTY))
00288                                         goto out;
00289                                 np = NULL;
00290                         }
00291                 }
00292         }
00293 
00294 done:   *lsnp = argp->prev_lsn;
00295         ret = 0;
00296 
00297 out:    /* Free any pages that weren't dirtied. */
00298         if (pp != NULL && (t_ret = __memp_fput(mpf, pp, 0)) != 0 && ret == 0)
00299                 ret = t_ret;
00300         if (lp != NULL && (t_ret = __memp_fput(mpf, lp, 0)) != 0 && ret == 0)
00301                 ret = t_ret;
00302         if (np != NULL && (t_ret = __memp_fput(mpf, np, 0)) != 0 && ret == 0)
00303                 ret = t_ret;
00304         if (rp != NULL && (t_ret = __memp_fput(mpf, rp, 0)) != 0 && ret == 0)
00305                 ret = t_ret;
00306 
00307         /* Free any allocated space. */
00308         if (_lp != NULL)
00309                 __os_free(dbenv, _lp);
00310         if (_rp != NULL)
00311                 __os_free(dbenv, _rp);
00312         if (sp != NULL)
00313                 __os_free(dbenv, sp);
00314 
00315         REC_CLOSE;
00316 }
00317 
00318 /*
00319  * __bam_rsplit_recover --
00320  *      Recovery function for a reverse split.
00321  *
00322  * PUBLIC: int __bam_rsplit_recover
00323  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00324  */
00325 int
00326 __bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
00327         DB_ENV *dbenv;
00328         DBT *dbtp;
00329         DB_LSN *lsnp;
00330         db_recops op;
00331         void *info;
00332 {
00333         __bam_rsplit_args *argp;
00334         DB *file_dbp;
00335         DBC *dbc;
00336         DB_LSN copy_lsn;
00337         DB_MPOOLFILE *mpf;
00338         PAGE *pagep;
00339         db_pgno_t pgno, root_pgno;
00340         db_recno_t rcnt;
00341         int cmp_n, cmp_p, modified, ret;
00342 
00343         pagep = NULL;
00344         COMPQUIET(info, NULL);
00345         REC_PRINT(__bam_rsplit_print);
00346         REC_INTRO(__bam_rsplit_read, 1, 1);
00347 
00348         /* Fix the root page. */
00349         pgno = root_pgno = argp->root_pgno;
00350         if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
00351                 if (ret != DB_PAGE_NOTFOUND
00352 #ifndef HAVE_FTRUNCATE
00353                      || DB_REDO(op)
00354 #endif
00355                      ) {
00356                         ret = __db_pgerr(file_dbp, pgno, ret);
00357                         goto out;
00358                 } else
00359                         goto do_page;
00360         }
00361 
00362         modified = 0;
00363         cmp_n = log_compare(lsnp, &LSN(pagep));
00364         cmp_p = log_compare(&LSN(pagep), &argp->rootlsn);
00365         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->rootlsn);
00366         if (cmp_p == 0 && DB_REDO(op)) {
00367                 /*
00368                  * Copy the new data to the root page.  If it is not now a
00369                  * leaf page we need to restore the record number.  We could
00370                  * try to determine if C_RECNUM was set in the btree, but
00371                  * that's not really necessary since the field is not used
00372                  * otherwise.
00373                  */
00374                 rcnt = RE_NREC(pagep);
00375                 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
00376                 if (LEVEL(pagep) > LEAFLEVEL)
00377                         RE_NREC_SET(pagep, rcnt);
00378                 pagep->pgno = root_pgno;
00379                 pagep->lsn = *lsnp;
00380                 modified = 1;
00381         } else if (cmp_n == 0 && DB_UNDO(op)) {
00382                 /* Need to undo update described. */
00383                 P_INIT(pagep, file_dbp->pgsize, root_pgno,
00384                     argp->nrec, PGNO_INVALID, pagep->level + 1,
00385                     IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO);
00386                 if ((ret = __db_pitem(dbc, pagep, 0,
00387                     argp->rootent.size, &argp->rootent, NULL)) != 0)
00388                         goto out;
00389                 pagep->lsn = argp->rootlsn;
00390                 modified = 1;
00391         }
00392         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00393                 goto out;
00394 
00395 do_page:
00396         /*
00397          * Fix the page copied over the root page.  It's possible that the
00398          * page never made it to disk, so if we're undo-ing and the page
00399          * doesn't exist, it's okay and there's nothing further to do.
00400          */
00401         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00402                 if (ret != DB_PAGE_NOTFOUND
00403 #ifndef HAVE_FTRUNCATE
00404                      || DB_REDO(op)
00405 #endif
00406                      ) {
00407                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00408                         goto out;
00409                 } else
00410                         goto done;
00411         }
00412         modified = 0;
00413         (void)__ua_memcpy(&copy_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
00414         cmp_n = log_compare(lsnp, &LSN(pagep));
00415         cmp_p = log_compare(&LSN(pagep), &copy_lsn);
00416         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &copy_lsn);
00417         if (cmp_p == 0 && DB_REDO(op)) {
00418                 /* Need to redo update described. */
00419                 pagep->lsn = *lsnp;
00420                 modified = 1;
00421         } else if (cmp_n == 0 && DB_UNDO(op)) {
00422                 /* Need to undo update described. */
00423                 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
00424                 modified = 1;
00425         }
00426         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00427                 goto out;
00428         pagep = NULL;
00429 
00430 done:   *lsnp = argp->prev_lsn;
00431         ret = 0;
00432 
00433 out:    if (pagep != NULL)
00434                 (void)__memp_fput(mpf, pagep, 0);
00435         REC_CLOSE;
00436 }
00437 
00438 /*
00439  * __bam_adj_recover --
00440  *      Recovery function for adj.
00441  *
00442  * PUBLIC: int __bam_adj_recover
00443  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00444  */
00445 int
00446 __bam_adj_recover(dbenv, dbtp, lsnp, op, info)
00447         DB_ENV *dbenv;
00448         DBT *dbtp;
00449         DB_LSN *lsnp;
00450         db_recops op;
00451         void *info;
00452 {
00453         __bam_adj_args *argp;
00454         DB *file_dbp;
00455         DBC *dbc;
00456         DB_MPOOLFILE *mpf;
00457         PAGE *pagep;
00458         int cmp_n, cmp_p, modified, ret;
00459 
00460         pagep = NULL;
00461         COMPQUIET(info, NULL);
00462         REC_PRINT(__bam_adj_print);
00463         REC_INTRO(__bam_adj_read, 1, 1);
00464 
00465         /* Get the page; if it never existed and we're undoing, we're done. */
00466         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00467                 if (ret != DB_PAGE_NOTFOUND
00468 #ifndef HAVE_FTRUNCATE
00469                      || DB_REDO(op)
00470 #endif
00471                      ) {
00472                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00473                         goto out;
00474                 } else
00475                         goto done;
00476         }
00477 
00478         modified = 0;
00479         cmp_n = log_compare(lsnp, &LSN(pagep));
00480         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
00481         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
00482         if (cmp_p == 0 && DB_REDO(op)) {
00483                 /* Need to redo update described. */
00484                 if ((ret = __bam_adjindx(dbc,
00485                     pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
00486                         goto out;
00487 
00488                 LSN(pagep) = *lsnp;
00489                 modified = 1;
00490         } else if (cmp_n == 0 && DB_UNDO(op)) {
00491                 /* Need to undo update described. */
00492                 if ((ret = __bam_adjindx(dbc,
00493                     pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
00494                         goto out;
00495 
00496                 LSN(pagep) = argp->lsn;
00497                 modified = 1;
00498         }
00499         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00500                 goto out;
00501         pagep = NULL;
00502 
00503 done:   *lsnp = argp->prev_lsn;
00504         ret = 0;
00505 
00506 out:    if (pagep != NULL)
00507                 (void)__memp_fput(mpf, pagep, 0);
00508         REC_CLOSE;
00509 }
00510 
00511 /*
00512  * __bam_cadjust_recover --
00513  *      Recovery function for the adjust of a count change in an internal
00514  *      page.
00515  *
00516  * PUBLIC: int __bam_cadjust_recover
00517  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00518  */
00519 int
00520 __bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
00521         DB_ENV *dbenv;
00522         DBT *dbtp;
00523         DB_LSN *lsnp;
00524         db_recops op;
00525         void *info;
00526 {
00527         __bam_cadjust_args *argp;
00528         DB *file_dbp;
00529         DBC *dbc;
00530         DB_MPOOLFILE *mpf;
00531         PAGE *pagep;
00532         int cmp_n, cmp_p, modified, ret;
00533 
00534         pagep = NULL;
00535         COMPQUIET(info, NULL);
00536         REC_PRINT(__bam_cadjust_print);
00537         REC_INTRO(__bam_cadjust_read, 1, 0);
00538 
00539         /* Get the page; if it never existed and we're undoing, we're done. */
00540         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00541                 if (ret != DB_PAGE_NOTFOUND
00542 #ifndef HAVE_FTRUNCATE
00543                      || DB_REDO(op)
00544 #endif
00545                      ) {
00546                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00547                         goto out;
00548                 } else
00549                         goto done;
00550         }
00551 
00552         modified = 0;
00553         cmp_n = log_compare(lsnp, &LSN(pagep));
00554         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
00555         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
00556         if (cmp_p == 0 && DB_REDO(op)) {
00557                 /* Need to redo update described. */
00558                 if (IS_BTREE_PAGE(pagep)) {
00559                         GET_BINTERNAL(file_dbp, pagep, argp->indx)->nrecs +=
00560                             argp->adjust;
00561                         if (argp->opflags & CAD_UPDATEROOT)
00562                                 RE_NREC_ADJ(pagep, argp->adjust);
00563                 } else {
00564                         GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs +=
00565                             argp->adjust;
00566                         if (argp->opflags & CAD_UPDATEROOT)
00567                                 RE_NREC_ADJ(pagep, argp->adjust);
00568                 }
00569 
00570                 LSN(pagep) = *lsnp;
00571                 modified = 1;
00572         } else if (cmp_n == 0 && DB_UNDO(op)) {
00573                 /* Need to undo update described. */
00574                 if (IS_BTREE_PAGE(pagep)) {
00575                         GET_BINTERNAL(file_dbp, pagep, argp->indx)->nrecs -=
00576                             argp->adjust;
00577                         if (argp->opflags & CAD_UPDATEROOT)
00578                                 RE_NREC_ADJ(pagep, -(argp->adjust));
00579                 } else {
00580                         GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs -=
00581                             argp->adjust;
00582                         if (argp->opflags & CAD_UPDATEROOT)
00583                                 RE_NREC_ADJ(pagep, -(argp->adjust));
00584                 }
00585                 LSN(pagep) = argp->lsn;
00586                 modified = 1;
00587         }
00588         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00589                 goto out;
00590         pagep = NULL;
00591 
00592 done:   *lsnp = argp->prev_lsn;
00593         ret = 0;
00594 
00595 out:    if (pagep != NULL)
00596                 (void)__memp_fput(mpf, pagep, 0);
00597         REC_CLOSE;
00598 }
00599 
00600 /*
00601  * __bam_cdel_recover --
00602  *      Recovery function for the intent-to-delete of a cursor record.
00603  *
00604  * PUBLIC: int __bam_cdel_recover
00605  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00606  */
00607 int
00608 __bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
00609         DB_ENV *dbenv;
00610         DBT *dbtp;
00611         DB_LSN *lsnp;
00612         db_recops op;
00613         void *info;
00614 {
00615         __bam_cdel_args *argp;
00616         DB *file_dbp;
00617         DBC *dbc;
00618         DB_MPOOLFILE *mpf;
00619         PAGE *pagep;
00620         u_int32_t indx;
00621         int cmp_n, cmp_p, modified, ret;
00622 
00623         pagep = NULL;
00624         COMPQUIET(info, NULL);
00625         REC_PRINT(__bam_cdel_print);
00626         REC_INTRO(__bam_cdel_read, 1, 0);
00627 
00628         /* Get the page; if it never existed and we're undoing, we're done. */
00629         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00630                 if (ret != DB_PAGE_NOTFOUND
00631 #ifndef HAVE_FTRUNCATE
00632                      || DB_REDO(op)
00633 #endif
00634                      ) {
00635                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00636                         goto out;
00637                 } else
00638                         goto done;
00639         }
00640 
00641         modified = 0;
00642         cmp_n = log_compare(lsnp, &LSN(pagep));
00643         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
00644         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
00645         if (cmp_p == 0 && DB_REDO(op)) {
00646                 /* Need to redo update described. */
00647                 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
00648                 B_DSET(GET_BKEYDATA(file_dbp, pagep, indx)->type);
00649 
00650                 LSN(pagep) = *lsnp;
00651                 modified = 1;
00652         } else if (cmp_n == 0 && DB_UNDO(op)) {
00653                 /* Need to undo update described. */
00654                 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
00655                 B_DCLR(GET_BKEYDATA(file_dbp, pagep, indx)->type);
00656 
00657                 if ((ret = __bam_ca_delete(
00658                     file_dbp, argp->pgno, argp->indx, 0, NULL)) != 0)
00659                         goto out;
00660 
00661                 LSN(pagep) = argp->lsn;
00662                 modified = 1;
00663         }
00664         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00665                 goto out;
00666         pagep = NULL;
00667 
00668 done:   *lsnp = argp->prev_lsn;
00669         ret = 0;
00670 
00671 out:    if (pagep != NULL)
00672                 (void)__memp_fput(mpf, pagep, 0);
00673         REC_CLOSE;
00674 }
00675 
00676 /*
00677  * __bam_repl_recover --
00678  *      Recovery function for page item replacement.
00679  *
00680  * PUBLIC: int __bam_repl_recover
00681  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00682  */
00683 int
00684 __bam_repl_recover(dbenv, dbtp, lsnp, op, info)
00685         DB_ENV *dbenv;
00686         DBT *dbtp;
00687         DB_LSN *lsnp;
00688         db_recops op;
00689         void *info;
00690 {
00691         __bam_repl_args *argp;
00692         BKEYDATA *bk;
00693         DB *file_dbp;
00694         DBC *dbc;
00695         DBT dbt;
00696         DB_MPOOLFILE *mpf;
00697         PAGE *pagep;
00698         int cmp_n, cmp_p, modified, ret;
00699         u_int8_t *p;
00700 
00701         pagep = NULL;
00702         COMPQUIET(info, NULL);
00703         REC_PRINT(__bam_repl_print);
00704         REC_INTRO(__bam_repl_read, 1, 1);
00705 
00706         /* Get the page; if it never existed and we're undoing, we're done. */
00707         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00708                 if (ret != DB_PAGE_NOTFOUND
00709 #ifndef HAVE_FTRUNCATE
00710                      || DB_REDO(op)
00711 #endif
00712                      ) {
00713                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00714                         goto out;
00715                 } else
00716                         goto done;
00717         }
00718         bk = GET_BKEYDATA(file_dbp, pagep, argp->indx);
00719 
00720         modified = 0;
00721         cmp_n = log_compare(lsnp, &LSN(pagep));
00722         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
00723         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
00724         if (cmp_p == 0 && DB_REDO(op)) {
00725                 /*
00726                  * Need to redo update described.
00727                  *
00728                  * Re-build the replacement item.
00729                  */
00730                 memset(&dbt, 0, sizeof(dbt));
00731                 dbt.size = argp->prefix + argp->suffix + argp->repl.size;
00732                 if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
00733                         goto out;
00734                 p = dbt.data;
00735                 memcpy(p, bk->data, argp->prefix);
00736                 p += argp->prefix;
00737                 memcpy(p, argp->repl.data, argp->repl.size);
00738                 p += argp->repl.size;
00739                 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
00740 
00741                 ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
00742                 __os_free(dbenv, dbt.data);
00743                 if (ret != 0)
00744                         goto out;
00745 
00746                 LSN(pagep) = *lsnp;
00747                 modified = 1;
00748         } else if (cmp_n == 0 && DB_UNDO(op)) {
00749                 /*
00750                  * Need to undo update described.
00751                  *
00752                  * Re-build the original item.
00753                  */
00754                 memset(&dbt, 0, sizeof(dbt));
00755                 dbt.size = argp->prefix + argp->suffix + argp->orig.size;
00756                 if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
00757                         goto out;
00758                 p = dbt.data;
00759                 memcpy(p, bk->data, argp->prefix);
00760                 p += argp->prefix;
00761                 memcpy(p, argp->orig.data, argp->orig.size);
00762                 p += argp->orig.size;
00763                 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
00764 
00765                 ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
00766                 __os_free(dbenv, dbt.data);
00767                 if (ret != 0)
00768                         goto out;
00769 
00770                 /* Reset the deleted flag, if necessary. */
00771                 if (argp->isdeleted)
00772                         B_DSET(GET_BKEYDATA(file_dbp, pagep, argp->indx)->type);
00773 
00774                 LSN(pagep) = argp->lsn;
00775                 modified = 1;
00776         }
00777         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00778                 goto out;
00779         pagep = NULL;
00780 
00781 done:   *lsnp = argp->prev_lsn;
00782         ret = 0;
00783 
00784 out:    if (pagep != NULL)
00785                 (void)__memp_fput(mpf, pagep, 0);
00786         REC_CLOSE;
00787 }
00788 
00789 /*
00790  * __bam_root_recover --
00791  *      Recovery function for setting the root page on the meta-data page.
00792  *
00793  * PUBLIC: int __bam_root_recover
00794  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00795  */
00796 int
00797 __bam_root_recover(dbenv, dbtp, lsnp, op, info)
00798         DB_ENV *dbenv;
00799         DBT *dbtp;
00800         DB_LSN *lsnp;
00801         db_recops op;
00802         void *info;
00803 {
00804         __bam_root_args *argp;
00805         BTMETA *meta;
00806         DB *file_dbp;
00807         DBC *dbc;
00808         DB_MPOOLFILE *mpf;
00809         int cmp_n, cmp_p, modified, ret;
00810 
00811         meta = NULL;
00812         COMPQUIET(info, NULL);
00813         REC_PRINT(__bam_root_print);
00814         REC_INTRO(__bam_root_read, 0, 0);
00815 
00816         if ((ret = __memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
00817                 if (ret != DB_PAGE_NOTFOUND
00818 #ifndef HAVE_FTRUNCATE
00819                      || DB_REDO(op)
00820 #endif
00821                      ) {
00822                         ret = __db_pgerr(file_dbp, argp->meta_pgno, ret);
00823                         goto out;
00824                 } else
00825                         goto done;
00826         }
00827 
00828         modified = 0;
00829         cmp_n = log_compare(lsnp, &LSN(meta));
00830         cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
00831         CHECK_LSN(dbenv, op, cmp_p, &LSN(meta), &argp->meta_lsn);
00832         if (cmp_p == 0 && DB_REDO(op)) {
00833                 /* Need to redo update described. */
00834                 meta->root = argp->root_pgno;
00835                 meta->dbmeta.lsn = *lsnp;
00836                 ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root;
00837                 modified = 1;
00838         } else if (cmp_n == 0 && DB_UNDO(op)) {
00839                 /* Nothing to undo except lsn. */
00840                 meta->dbmeta.lsn = argp->meta_lsn;
00841                 modified = 1;
00842         }
00843         if ((ret = __memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00844                 goto out;
00845         meta = NULL;
00846 
00847 done:   *lsnp = argp->prev_lsn;
00848         ret = 0;
00849 
00850 out:    if (meta != NULL)
00851                 (void)__memp_fput(mpf, meta, 0);
00852         REC_CLOSE;
00853 }
00854 
00855 /*
00856  * __bam_curadj_recover --
00857  *      Transaction abort function to undo cursor adjustments.
00858  *      This should only be triggered by subtransaction aborts.
00859  *
00860  * PUBLIC: int __bam_curadj_recover
00861  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00862  */
00863 int
00864 __bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
00865         DB_ENV *dbenv;
00866         DBT *dbtp;
00867         DB_LSN *lsnp;
00868         db_recops op;
00869         void *info;
00870 {
00871         __bam_curadj_args *argp;
00872         DB *file_dbp;
00873         DBC *dbc;
00874         DB_MPOOLFILE *mpf;
00875         int ret;
00876 
00877         COMPQUIET(info, NULL);
00878         COMPQUIET(mpf, NULL);
00879 
00880         REC_PRINT(__bam_curadj_print);
00881         REC_INTRO(__bam_curadj_read, 0, 1);
00882 
00883         ret = 0;
00884         if (op != DB_TXN_ABORT)
00885                 goto done;
00886 
00887         switch (argp->mode) {
00888         case DB_CA_DI:
00889                 if ((ret = __bam_ca_di(dbc, argp->from_pgno,
00890                     argp->from_indx, -(int)argp->first_indx)) != 0)
00891                         goto out;
00892                 break;
00893         case DB_CA_DUP:
00894                 if ((ret = __bam_ca_undodup(file_dbp, argp->first_indx,
00895                     argp->from_pgno, argp->from_indx, argp->to_indx)) != 0)
00896                         goto out;
00897                 break;
00898 
00899         case DB_CA_RSPLIT:
00900                 if ((ret =
00901                     __bam_ca_rsplit(dbc, argp->to_pgno, argp->from_pgno)) != 0)
00902                         goto out;
00903                 break;
00904 
00905         case DB_CA_SPLIT:
00906                 if ((ret = __bam_ca_undosplit(file_dbp, argp->from_pgno,
00907                     argp->to_pgno, argp->left_pgno, argp->from_indx)) != 0)
00908                         goto out;
00909                 break;
00910         }
00911 
00912 done:   *lsnp = argp->prev_lsn;
00913 out:    REC_CLOSE;
00914 }
00915 
00916 /*
00917  * __bam_rcuradj_recover --
00918  *      Transaction abort function to undo cursor adjustments in rrecno.
00919  *      This should only be triggered by subtransaction aborts.
00920  *
00921  * PUBLIC: int __bam_rcuradj_recover
00922  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00923  */
00924 int
00925 __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
00926         DB_ENV *dbenv;
00927         DBT *dbtp;
00928         DB_LSN *lsnp;
00929         db_recops op;
00930         void *info;
00931 {
00932         __bam_rcuradj_args *argp;
00933         BTREE_CURSOR *cp;
00934         DB *file_dbp;
00935         DBC *dbc, *rdbc;
00936         DB_MPOOLFILE *mpf;
00937         int ret, t_ret;
00938 
00939         COMPQUIET(info, NULL);
00940         COMPQUIET(mpf, NULL);
00941         rdbc = NULL;
00942 
00943         REC_PRINT(__bam_rcuradj_print);
00944         REC_INTRO(__bam_rcuradj_read, 0, 1);
00945 
00946         ret = t_ret = 0;
00947 
00948         if (op != DB_TXN_ABORT)
00949                 goto done;
00950 
00951         /*
00952          * We don't know whether we're in an offpage dup set, and
00953          * thus don't know whether the dbc REC_INTRO has handed us is
00954          * of a reasonable type.  It's certainly unset, so if this is
00955          * an offpage dup set, we don't have an OPD cursor.  The
00956          * simplest solution is just to allocate a whole new cursor
00957          * for our use;  we're only really using it to hold pass some
00958          * state into __ram_ca, and this way we don't need to make
00959          * this function know anything about how offpage dups work.
00960          */
00961         if ((ret = __db_cursor_int(file_dbp,
00962                 NULL, DB_RECNO, argp->root, 0, DB_LOCK_INVALIDID, &rdbc)) != 0)
00963                 goto out;
00964 
00965         cp = (BTREE_CURSOR *)rdbc->internal;
00966         F_SET(cp, C_RENUMBER);
00967         cp->recno = argp->recno;
00968 
00969         switch (argp->mode) {
00970         case CA_DELETE:
00971                 /*
00972                  * The way to undo a delete is with an insert.  Since
00973                  * we're undoing it, the delete flag must be set.
00974                  */
00975                 F_SET(cp, C_DELETED);
00976                 F_SET(cp, C_RENUMBER);  /* Just in case. */
00977                 cp->order = argp->order;
00978                 (void)__ram_ca(rdbc, CA_ICURRENT);
00979                 break;
00980         case CA_IAFTER:
00981         case CA_IBEFORE:
00982         case CA_ICURRENT:
00983                 /*
00984                  * The way to undo an insert is with a delete.  The delete
00985                  * flag is unset to start with.
00986                  */
00987                 F_CLR(cp, C_DELETED);
00988                 cp->order = INVALID_ORDER;
00989                 (void)__ram_ca(rdbc, CA_DELETE);
00990                 break;
00991         }
00992 
00993 done:   *lsnp = argp->prev_lsn;
00994 out:    if (rdbc != NULL && (t_ret = __db_c_close(rdbc)) != 0 && ret == 0)
00995                 ret = t_ret;
00996         REC_CLOSE;
00997 }
00998 
00999 /*
01000  * __bam_relink_recover --
01001  *      Recovery function for relink.
01002  *
01003  * PUBLIC: int __bam_relink_recover
01004  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01005  */
01006 int
01007 __bam_relink_recover(dbenv, dbtp, lsnp, op, info)
01008         DB_ENV *dbenv;
01009         DBT *dbtp;
01010         DB_LSN *lsnp;
01011         db_recops op;
01012         void *info;
01013 {
01014         __bam_relink_args *argp;
01015         DB *file_dbp;
01016         DBC *dbc;
01017         DB_MPOOLFILE *mpf;
01018         PAGE *pagep;
01019         int cmp_n, cmp_p, modified, ret;
01020 
01021         pagep = NULL;
01022         COMPQUIET(info, NULL);
01023         REC_PRINT(__bam_relink_print);
01024         REC_INTRO(__bam_relink_read, 1, 0);
01025 
01026         /*
01027          * There are up to three pages we need to check -- the page, and the
01028          * previous and next pages, if they existed.  For a page add operation,
01029          * the current page is the result of a split and is being recovered
01030          * elsewhere, so all we need do is recover the next page.
01031          */
01032         if ((ret = __memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
01033                 if (ret != DB_PAGE_NOTFOUND
01034 #ifndef HAVE_FTRUNCATE
01035                      || DB_REDO(op)
01036 #endif
01037                      ) {
01038                         ret = __db_pgerr(file_dbp, argp->next, ret);
01039                         goto out;
01040                 } else
01041                         goto prev;
01042         }
01043 
01044         modified = 0;
01045         cmp_n = log_compare(lsnp, &LSN(pagep));
01046         cmp_p = log_compare(&LSN(pagep), &argp->lsn_next);
01047         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn_next);
01048         if (cmp_p == 0 && DB_REDO(op)) {
01049                 /* Redo the remove or replace. */
01050                 if (argp->new_pgno == PGNO_INVALID)
01051                         pagep->prev_pgno = argp->prev;
01052                 else
01053                         pagep->prev_pgno = argp->new_pgno;
01054 
01055                 pagep->lsn = *lsnp;
01056                 modified = 1;
01057         } else if (cmp_n == 0 && DB_UNDO(op)) {
01058                 /* Undo the remove or replace. */
01059                 pagep->prev_pgno = argp->pgno;
01060 
01061                 pagep->lsn = argp->lsn_next;
01062                 modified = 1;
01063         }
01064 
01065         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01066                 goto out;
01067         pagep = NULL;
01068 
01069 prev: if ((ret = __memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
01070                 if (ret != DB_PAGE_NOTFOUND
01071 #ifndef HAVE_FTRUNCATE
01072                      || DB_REDO(op)
01073 #endif
01074                      ) {
01075                         ret = __db_pgerr(file_dbp, argp->prev, ret);
01076                         goto out;
01077                 } else
01078                         goto done;
01079         }
01080 
01081         modified = 0;
01082         cmp_p = log_compare(&LSN(pagep), &argp->lsn_prev);
01083         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->lsn_prev);
01084         if (cmp_p == 0 && DB_REDO(op)) {
01085                 /* Redo the relink. */
01086                 if (argp->new_pgno == PGNO_INVALID)
01087                         pagep->next_pgno = argp->next;
01088                 else
01089                         pagep->next_pgno = argp->new_pgno;
01090 
01091                 pagep->lsn = *lsnp;
01092                 modified = 1;
01093         } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
01094                 /* Undo the relink. */
01095                 pagep->next_pgno = argp->pgno;
01096                 pagep->lsn = argp->lsn_prev;
01097 
01098                 modified = 1;
01099         }
01100 
01101         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01102                 goto out;
01103         pagep = NULL;
01104 
01105 done:   *lsnp = argp->prev_lsn;
01106         ret = 0;
01107 
01108 out:    if (pagep != NULL)
01109                 (void)__memp_fput(mpf, pagep, 0);
01110         REC_CLOSE;
01111 }
01112 
01113 /*
01114  * __bam_merge_recover --
01115  *      Recovery function for merge.
01116  *
01117  * PUBLIC: int __bam_merge_recover
01118  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01119  */
01120 int
01121 __bam_merge_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         __bam_merge_args *argp;
01129         BKEYDATA *bk;
01130         DB *file_dbp;
01131         DBC *dbc;
01132         DB_MPOOLFILE *mpf;
01133         PAGE *pagep;
01134         db_indx_t indx, *ninp, *pinp;
01135         u_int32_t size;
01136         u_int8_t *bp;
01137         int cmp_n, cmp_p, i, modified, ret;
01138 
01139         COMPQUIET(info, NULL);
01140 
01141         REC_PRINT(__bam_merge_print);
01142         REC_INTRO(__bam_merge_read, 1, 1);
01143 
01144         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
01145                 if (ret != DB_PAGE_NOTFOUND
01146 #ifndef HAVE_FTRUNCATE
01147                      || DB_REDO(op)
01148 #endif
01149                      ) {
01150                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
01151                         goto out;
01152                 } else
01153                         goto next;
01154         }
01155 
01156         modified = 0;
01157         cmp_n = log_compare(lsnp, &LSN(pagep));
01158         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
01159         CHECK_LSN(file_dbp->dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
01160 
01161         if (cmp_p == 0 && DB_REDO(op)) {
01162                 /*
01163                  * If the header is provided the page is empty, copy the
01164                  * needed data.
01165                  */
01166                 DB_ASSERT(argp->hdr.size == 0 || NUM_ENT(pagep) == 0);
01167                 if (argp->hdr.size != 0) {
01168                         P_INIT(pagep, file_dbp->pgsize, pagep->pgno,
01169                              PREV_PGNO(argp->hdr.data),
01170                              NEXT_PGNO(argp->hdr.data),
01171                              LEVEL(argp->hdr.data), TYPE(argp->hdr.data));
01172                 }
01173                 if (TYPE(pagep) == P_OVERFLOW) {
01174                         OV_REF(pagep) = OV_REF(argp->hdr.data);
01175                         OV_LEN(pagep) = OV_LEN(argp->hdr.data);
01176                         bp = (u_int8_t *) pagep + P_OVERHEAD(file_dbp);
01177                         memcpy(bp, argp->data.data, argp->data.size);
01178                 } else {
01179                         /* Copy the data segment. */
01180                         bp = (u_int8_t *)pagep +
01181                              (db_indx_t)(HOFFSET(pagep) - argp->data.size);
01182                         memcpy(bp, argp->data.data, argp->data.size);
01183 
01184                         /* Copy index table offset past the current entries. */
01185                         pinp = P_INP(file_dbp, pagep) + NUM_ENT(pagep);
01186                         ninp = argp->ind.data;
01187                         for (i = 0;
01188                              i < (int)(argp->ind.size / sizeof(*ninp)); i++)
01189                                 *pinp++ = *ninp++
01190                                       - (file_dbp->pgsize - HOFFSET(pagep));
01191                         HOFFSET(pagep) -= argp->data.size;
01192                         NUM_ENT(pagep) += i;
01193                 }
01194                 pagep->lsn = *lsnp;
01195                 modified = 1;
01196         } else if (cmp_n == 0 && !DB_REDO(op)) {
01197                 /*
01198                  * Since logging is logical at the page level
01199                  * we cannot just truncate the data space.  Delete
01200                  * the proper number of items from the logical end
01201                  * of the page.
01202                  */
01203                 for (i = 0; i < (int)(argp->ind.size / sizeof(*ninp)); i++) {
01204                         indx = NUM_ENT(pagep) - 1;
01205                         if (P_INP(file_dbp, pagep)[indx] ==
01206                              P_INP(file_dbp, pagep)[indx - P_INDX]) {
01207                                 NUM_ENT(pagep)--;
01208                                 continue;
01209                         }
01210                         switch (TYPE(pagep)) {
01211                         case P_LBTREE:
01212                         case P_LRECNO:
01213                         case P_LDUP:
01214                                 bk = GET_BKEYDATA(file_dbp, pagep, indx);
01215                                 size = BITEM_SIZE(bk);
01216                                 break;
01217 
01218                         case P_IBTREE:
01219                                 size = BINTERNAL_SIZE(
01220                                      GET_BINTERNAL(file_dbp, pagep, indx)->len);
01221                                 break;
01222                         case P_IRECNO:
01223                                 size = RINTERNAL_SIZE;
01224                                 break;
01225 
01226                         default:
01227                                 ret = __db_pgfmt(dbenv, PGNO(pagep));
01228                                 goto out;
01229                         }
01230                         if ((ret =
01231                              __db_ditem(dbc, pagep, indx, size)) != 0)
01232                                 goto out;
01233                 }
01234                 if (argp->ind.size == 0)
01235                         HOFFSET(pagep) = file_dbp->pgsize;
01236                 pagep->lsn = argp->lsn;
01237                 modified = 1;
01238         }
01239 
01240         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01241                 goto out;
01242 
01243 next:   if ((ret = __memp_fget(mpf, &argp->npgno, 0, &pagep)) != 0) {
01244                 if (ret != DB_PAGE_NOTFOUND
01245 #ifndef HAVE_FTRUNCATE
01246                      || DB_REDO(op)
01247 #endif
01248                      ) {
01249                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
01250                         goto out;
01251                 } else
01252                         goto done;
01253         }
01254 
01255         modified = 0;
01256         cmp_n = log_compare(lsnp, &LSN(pagep));
01257         cmp_p = log_compare(&LSN(pagep), &argp->nlsn);
01258         CHECK_LSN(file_dbp->dbenv, op, cmp_p, &LSN(pagep), &argp->nlsn);
01259 
01260         if (cmp_p == 0 && DB_REDO(op)) {
01261                 /* Need to truncate the page. */
01262                 HOFFSET(pagep) = file_dbp->pgsize;
01263                 NUM_ENT(pagep) = 0;
01264                 pagep->lsn = *lsnp;
01265                 modified = 1;
01266         } else if (cmp_n == 0 && !DB_REDO(op)) {
01267                 /* Need to put the data back on the page. */
01268                 if (TYPE(pagep) == P_OVERFLOW) {
01269                         OV_REF(pagep) = OV_REF(argp->hdr.data);
01270                         OV_LEN(pagep) = OV_LEN(argp->hdr.data);
01271                         bp = (u_int8_t *) pagep + P_OVERHEAD(file_dbp);
01272                         memcpy(bp, argp->data.data, argp->data.size);
01273                 } else {
01274                         bp = (u_int8_t *)pagep +
01275                              (db_indx_t)(HOFFSET(pagep) - argp->data.size);
01276                         memcpy(bp, argp->data.data, argp->data.size);
01277 
01278                         /* Copy index table. */
01279                         pinp = P_INP(file_dbp, pagep) + NUM_ENT(pagep);
01280                         ninp = argp->ind.data;
01281                         for (i = 0;
01282                             i < (int)(argp->ind.size / sizeof(*ninp)); i++)
01283                                 *pinp++ = *ninp++;
01284                         HOFFSET(pagep) -= argp->data.size;
01285                         NUM_ENT(pagep) = i;
01286                 }
01287                 pagep->lsn = argp->nlsn;
01288                 modified = 1;
01289         }
01290 
01291         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01292                 goto out;
01293 done:
01294         *lsnp = argp->prev_lsn;
01295         ret = 0;
01296 
01297 out:    REC_CLOSE;
01298 }
01299 
01300 /*
01301  * __bam_pgno_recover --
01302  *      Recovery function for page number replacment.
01303  *
01304  * PUBLIC: int __bam_pgno_recover
01305  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01306  */
01307 int
01308 __bam_pgno_recover(dbenv, dbtp, lsnp, op, info)
01309         DB_ENV *dbenv;
01310         DBT *dbtp;
01311         DB_LSN *lsnp;
01312         db_recops op;
01313         void *info;
01314 {
01315         BINTERNAL *bi;
01316         __bam_pgno_args *argp;
01317         DB *file_dbp;
01318         DBC *dbc;
01319         DB_MPOOLFILE *mpf;
01320         PAGE *pagep, *npagep;
01321         db_pgno_t *pgnop;
01322         int cmp_n, cmp_p, modified, ret;
01323 
01324         COMPQUIET(info, NULL);
01325 
01326         REC_PRINT(__bam_pgno_print);
01327         REC_INTRO(__bam_pgno_read, 1, 0);
01328 
01329         REC_FGET(mpf, argp->pgno, &pagep, done);
01330 
01331         modified = 0;
01332         cmp_n = log_compare(lsnp, &LSN(pagep));
01333         cmp_p = log_compare(&LSN(pagep), &argp->lsn);
01334         CHECK_LSN(file_dbp->dbenv, op, cmp_p, &LSN(pagep), &argp->lsn);
01335 
01336         if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && !DB_REDO(op))) {
01337                 switch (TYPE(pagep)) {
01338                 case P_IBTREE:
01339                         /*
01340                          * An internal record can have both a overflow
01341                          * and child pointer.  Fetch the page to see
01342                          * which it is.
01343                          */
01344                         bi = GET_BINTERNAL(file_dbp, pagep, argp->indx);
01345                         if (B_TYPE(bi->type) == B_OVERFLOW) {
01346                                 REC_FGET(mpf, argp->npgno, &npagep, out);
01347 
01348                                 if (TYPE(npagep) == P_OVERFLOW)
01349                                         pgnop =
01350                                              &((BOVERFLOW *)(bi->data))->pgno;
01351                                 else
01352                                         pgnop = &bi->pgno;
01353                                 if ((ret = __memp_fput(mpf, npagep, 0)) != 0)
01354                                         goto out;
01355                                 break;
01356                         }
01357                         pgnop = &bi->pgno;
01358                         break;
01359                 case P_IRECNO:
01360                         pgnop =
01361                              &GET_RINTERNAL(file_dbp, pagep, argp->indx)->pgno;
01362                         break;
01363                 default:
01364                         pgnop =
01365                              &GET_BOVERFLOW(file_dbp, pagep, argp->indx)->pgno;
01366                         break;
01367                 }
01368 
01369                 if (DB_REDO(op)) {
01370                         /* Need to redo update described. */
01371                         *pgnop = argp->npgno;
01372                         pagep->lsn = *lsnp;
01373                         modified = 1;
01374                 } else {
01375                         *pgnop = argp->opgno;
01376                         pagep->lsn = argp->lsn;
01377                         modified = 1;
01378                 }
01379         }
01380 
01381         if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01382                 goto out;
01383 
01384 done:
01385         *lsnp = argp->prev_lsn;
01386         ret = 0;
01387 
01388 out:    REC_CLOSE;
01389 }

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