bt_rec.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: bt__rec_8c-source.html,v 1.1 2008/06/08 10:13:39 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "db_page.h"
00022 #include "hash.h"
00023 #include "btree.h"
00024 #include "log.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  * CDB___bam_pg_alloc_recover --
00032  *      Recovery function for pg_alloc.
00033  *
00034  * PUBLIC: int CDB___bam_pg_alloc_recover
00035  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00036  */
00037 int
00038 CDB___bam_pg_alloc_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_pg_alloc_args *argp;
00046         DB *file_dbp;
00047         DBC *dbc;
00048         DBMETA *meta;
00049         DB_MPOOLFILE *mpf;
00050         PAGE *pagep;
00051         db_pgno_t pgno;
00052         int cmp_n, cmp_p, modified, ret;
00053 
00054         COMPQUIET(info, NULL);
00055         REC_PRINT(CDB___bam_pg_alloc_print);
00056         REC_INTRO(CDB___bam_pg_alloc_read, 0);
00057 
00058         /*
00059          * Fix up the allocated page.  If we're redoing the operation, we have
00060          * to get the page (creating it if it doesn't exist), and update its
00061          * LSN.  If we're undoing the operation, we have to reset the page's
00062          * LSN and put it on the free list.
00063          *
00064          * Fix up the metadata page.  If we're redoing the operation, we have
00065          * to get the metadata page and update its LSN and its free pointer.
00066          * If we're undoing the operation and the page was ever created, we put
00067          * it on the freelist.
00068          */
00069         pgno = PGNO_BASE_MD;
00070         if ((ret = CDB_memp_fget(mpf, &pgno, 0, &meta)) != 0) {
00071                 /* The metadata page must always exist on redo. */
00072                 if (DB_REDO(op)) {
00073                         (void)CDB___db_pgerr(file_dbp, pgno);
00074                         goto out;
00075                 } else
00076                         goto done;
00077         }
00078         if ((ret = CDB_memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00079                 /*
00080                  * We specify creation and check for it later, because this
00081                  * operation was supposed to create the page, and even in
00082                  * the undo case it's going to get linked onto the freelist
00083                  * which we're also fixing up.
00084                  */
00085                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00086                 (void)CDB_memp_fput(mpf, meta, 0);
00087                 goto out;
00088         }
00089 
00090         /* Fix up the allocated page. */
00091         modified = 0;
00092         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00093         cmp_p = CDB_log_compare(&LSN(pagep), &argp->page_lsn);
00094         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->page_lsn);
00095         if (cmp_p == 0 && DB_REDO(op)) {
00096                 /* Need to redo update described. */
00097                 P_INIT(pagep, file_dbp->pgsize,
00098                     argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, TYPE(argp), TAGS(argp));
00099 
00100                 pagep->lsn = *lsnp;
00101                 modified = 1;
00102         } else if (cmp_n == 0 && DB_UNDO(op)) {
00103                 /* Need to undo update described. */
00104                 P_INIT(pagep, file_dbp->pgsize,
00105                     argp->pgno, PGNO_INVALID, meta->free, 0, P_INVALID, 0);
00106 
00107                 pagep->lsn = argp->page_lsn;
00108                 modified = 1;
00109         }
00110         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
00111                 (void)CDB_memp_fput(mpf, meta, 0);
00112                 goto out;
00113         }
00114 
00115         /* Fix up the metadata page. */
00116         modified = 0;
00117         cmp_n = CDB_log_compare(lsnp, &meta->alloc_lsn);
00118         cmp_p = CDB_log_compare(&meta->alloc_lsn, &argp->alloc_lsn);
00119         CHECK_LSN(op, cmp_p, &meta->alloc_lsn, &argp->alloc_lsn);
00120         if (cmp_p == 0 && DB_REDO(op)) {
00121                 /* Need to redo update described. */
00122                 meta->alloc_lsn = *lsnp;
00123                 if (CDB_log_compare(&LSN(meta), &argp->meta_lsn) == 0)
00124                         LSN(meta) = *lsnp;
00125                 meta->free = argp->next;
00126                 modified = 1;
00127         } else if (cmp_n == 0 && DB_UNDO(op)) {
00128                 /* Need to undo update described. */
00129                 meta->alloc_lsn = argp->alloc_lsn;
00130                 if (CDB_log_compare(lsnp, &LSN(meta)) == 0)
00131                         LSN(meta) = argp->meta_lsn;
00132                 meta->free = argp->pgno;
00133                 modified = 1;
00134         }
00135         if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00136                 goto out;
00137         /*
00138          * This could be the metapage from a subdb which is read from disk
00139          * to recover its creation.
00140          */
00141         if (F_ISSET(file_dbp, DB_AM_SUBDB)) {
00142                 switch (argp->type) {
00143                    case P_HASHMETA:
00144                    case P_BTREEMETA:
00145                    case P_QAMMETA:
00146                         file_dbp->sync(file_dbp, 0);
00147                 }
00148         }
00149 
00150 done:   *lsnp = argp->prev_lsn;
00151         ret = 0;
00152 
00153 out:    REC_CLOSE;
00154 }
00155 
00156 /*
00157  * CDB___bam_pg_free_recover --
00158  *      Recovery function for pg_free.
00159  *
00160  * PUBLIC: int CDB___bam_pg_free_recover
00161  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00162  */
00163 int
00164 CDB___bam_pg_free_recover(dbenv, dbtp, lsnp, op, info)
00165         DB_ENV *dbenv;
00166         DBT *dbtp;
00167         DB_LSN *lsnp;
00168         db_recops op;
00169         void *info;
00170 {
00171         __bam_pg_free_args *argp;
00172         DB *file_dbp;
00173         DBC *dbc;
00174         DBMETA *meta;
00175         DB_LSN copy_lsn;
00176         DB_MPOOLFILE *mpf;
00177         PAGE *pagep;
00178         db_pgno_t pgno;
00179         int cmp_n, cmp_p, modified, ret;
00180 
00181         COMPQUIET(info, NULL);
00182         REC_PRINT(CDB___bam_pg_free_print);
00183         REC_INTRO(CDB___bam_pg_free_read, 1);
00184 
00185         /*
00186          * Fix up the freed page.  If we're redoing the operation we get the
00187          * page and explicitly discard its contents, then update its LSN.  If
00188          * we're undoing the operation, we get the page and restore its header.
00189          */
00190         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00191                 /*
00192                  * We don't automatically create the page.  The only way the
00193                  * page might not exist is if the alloc never happened, and
00194                  * the only way the alloc might never have happened is if we
00195                  * are undoing, in which case there's no reason to create the
00196                  * page.
00197                  */
00198                 if (DB_UNDO(op))
00199                         goto done;
00200                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00201                 goto out;
00202         }
00203         modified = 0;
00204         CDB___ua_memcpy(&copy_lsn, &LSN(argp->header.data), sizeof(DB_LSN));
00205         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00206         cmp_p = CDB_log_compare(&LSN(pagep), &copy_lsn);
00207         CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
00208         if (cmp_p == 0 && DB_REDO(op)) {
00209                 /* Need to redo update described. */
00210                 P_INIT(pagep, file_dbp->pgsize,
00211                     pagep->pgno, PGNO_INVALID, argp->next, 0, P_INVALID, 0);
00212                 pagep->lsn = *lsnp;
00213 
00214                 modified = 1;
00215         } else if (cmp_n == 0 && DB_UNDO(op)) {
00216                 /* Need to undo update described. */
00217                 memcpy(pagep, argp->header.data, argp->header.size);
00218 
00219                 modified = 1;
00220         }
00221         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00222                 goto out;
00223 
00224         /*
00225          * Fix up the metadata page.  If we're redoing or undoing the operation
00226          * we get the page and update its LSN and free pointer.
00227          */
00228         pgno = PGNO_BASE_MD;
00229         if ((ret = CDB_memp_fget(mpf, &pgno, 0, &meta)) != 0) {
00230                 /* The metadata page must always exist. */
00231                 (void)CDB___db_pgerr(file_dbp, pgno);
00232                 goto out;
00233         }
00234 
00235         modified = 0;
00236         cmp_n = CDB_log_compare(lsnp, &meta->alloc_lsn);
00237         cmp_p = CDB_log_compare(&meta->alloc_lsn, &argp->alloc_lsn);
00238         CHECK_LSN(op, cmp_p, &meta->alloc_lsn, &argp->alloc_lsn);
00239         if (cmp_p == 0 && DB_REDO(op)) {
00240                 /* Need to redo update described. */
00241                 meta->free = argp->pgno;
00242 
00243                 meta->alloc_lsn = *lsnp;
00244                 if (CDB_log_compare(&LSN(meta), &argp->meta_lsn) == 0)
00245                         LSN(meta) = *lsnp;
00246                 modified = 1;
00247         } else if (cmp_n == 0 && DB_UNDO(op)) {
00248                 /* Need to undo update described. */
00249                 meta->free = argp->next;
00250 
00251                 meta->alloc_lsn = argp->alloc_lsn;
00252                 if (CDB_log_compare(lsnp, &LSN(meta)) == 0)
00253                         LSN(meta) = argp->meta_lsn;
00254                 modified = 1;
00255         }
00256         if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00257                 goto out;
00258 
00259 done:   *lsnp = argp->prev_lsn;
00260         ret = 0;
00261 
00262 out:    REC_CLOSE;
00263 }
00264 
00265 /*
00266  * CDB___bam_split_recover --
00267  *      Recovery function for split.
00268  *
00269  * PUBLIC: int CDB___bam_split_recover
00270  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00271  */
00272 int
00273 CDB___bam_split_recover(dbenv, dbtp, lsnp, op, info)
00274         DB_ENV *dbenv;
00275         DBT *dbtp;
00276         DB_LSN *lsnp;
00277         db_recops op;
00278         void *info;
00279 {
00280         __bam_split_args *argp;
00281         DB *file_dbp;
00282         DBC *dbc;
00283         DB_MPOOLFILE *mpf;
00284         PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
00285         db_pgno_t pgno, root_pgno;
00286         u_int32_t ptype;
00287         int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret;
00288 
00289         COMPQUIET(info, NULL);
00290         REC_PRINT(CDB___bam_split_print);
00291 
00292         mpf = NULL;
00293         _lp = lp = np = pp = _rp = rp = NULL;
00294         sp = NULL;
00295 
00296         REC_INTRO(CDB___bam_split_read, 1);
00297 
00298         /*
00299          * There are two kinds of splits that we have to recover from.  The
00300          * first is a root-page split, where the root page is split from a
00301          * leaf page into an internal page and two new leaf pages are created.
00302          * The second is where a page is split into two pages, and a new key
00303          * is inserted into the parent page.
00304          *
00305          * DBTs are not aligned in log records, so we need to copy the page
00306          * so that we can access fields within it throughout this routine.
00307          * Although we could hardcode the unaligned copies in this routine,
00308          * we will be calling into regular btree functions with this page,
00309          * so it's got to be aligned.  Copying it into allocated memory is
00310          * the only way to guarantee this.
00311          */
00312         if ((ret = CDB___os_malloc(dbenv, argp->pg.size, NULL, &sp)) != 0)
00313                 goto out;
00314         memcpy(sp, argp->pg.data, argp->pg.size);
00315 
00316         pgno = PGNO(sp);
00317         root_pgno = argp->root_pgno;
00318         rootsplit = pgno == root_pgno;
00319         if (CDB_memp_fget(mpf, &argp->left, 0, &lp) != 0)
00320                 lp = NULL;
00321         if (CDB_memp_fget(mpf, &argp->right, 0, &rp) != 0)
00322                 rp = NULL;
00323 
00324         if (DB_REDO(op)) {
00325                 l_update = r_update = p_update = 0;
00326                 /*
00327                  * Decide if we need to resplit the page.
00328                  *
00329                  * If this is a root split, then the root has to exist, it's
00330                  * the page we're splitting and it gets modified.  If this is
00331                  * not a root split, then the left page has to exist, for the
00332                  * same reason.
00333                  */
00334                 if (rootsplit) {
00335                         if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pp)) != 0) {
00336                                 (void)CDB___db_pgerr(file_dbp, pgno);
00337                                 pp = NULL;
00338                                 goto out;
00339                         }
00340                         cmp = CDB_log_compare(&LSN(pp), &LSN(argp->pg.data));
00341                         CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data));
00342                         p_update = cmp  == 0;
00343                 } else if (lp == NULL) {
00344                         (void)CDB___db_pgerr(file_dbp, argp->left);
00345                         goto out;
00346                 }
00347 
00348                 if (lp != NULL) {
00349                         cmp = CDB_log_compare(&LSN(lp), &argp->llsn);
00350                         CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn);
00351                         if (cmp == 0)
00352                                 l_update = 1;
00353                 } else
00354                         l_update = 1;
00355 
00356                 if (rp != NULL) {
00357                         cmp = CDB_log_compare(&LSN(rp), &argp->rlsn);
00358                         CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn);
00359                         if (cmp == 0)
00360                                 r_update = 1;
00361                 } else
00362                         r_update = 1;
00363                 if (!p_update && !l_update && !r_update)
00364                         goto check_next;
00365 
00366                 /* Allocate and initialize new left/right child pages. */
00367                 if ((ret =
00368                     CDB___os_malloc(dbenv, file_dbp->pgsize, NULL, &_lp)) != 0
00369                     || (ret =
00370                     CDB___os_malloc(dbenv, file_dbp->pgsize, NULL, &_rp)) != 0)
00371                         goto out;
00372                 if (rootsplit) {
00373                         P_INIT(_lp, file_dbp->pgsize, argp->left,
00374                             PGNO_INVALID,
00375                             ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
00376                             LEVEL(sp), TYPE(sp), TAGS(sp));
00377                         P_INIT(_rp, file_dbp->pgsize, argp->right,
00378                             ISINTERNAL(sp) ?  PGNO_INVALID : argp->left,
00379                             PGNO_INVALID, LEVEL(sp), TYPE(sp), TAGS(sp));
00380                 } else {
00381                         P_INIT(_lp, file_dbp->pgsize, PGNO(sp),
00382                             ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp),
00383                             ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
00384                             LEVEL(sp), TYPE(sp), TAGS(sp));
00385                         P_INIT(_rp, file_dbp->pgsize, argp->right,
00386                             ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno,
00387                             ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp),
00388                             LEVEL(sp), TYPE(sp), TAGS(sp));
00389                 }
00390 
00391                 /* Split the page. */
00392                 if ((ret = CDB___bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 ||
00393                     (ret = CDB___bam_copy(file_dbp, sp, _rp, argp->indx,
00394                     NUM_ENT(sp))) != 0)
00395                         goto out;
00396 
00397                 /* If the left child is wrong, update it. */
00398                 if (lp == NULL && (ret =
00399                     CDB_memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) {
00400                         (void)CDB___db_pgerr(file_dbp, argp->left);
00401                         lp = NULL;
00402                         goto out;
00403                 }
00404                 if (l_update) {
00405                         memcpy(lp, _lp, file_dbp->pgsize);
00406                         lp->lsn = *lsnp;
00407                         if ((ret = CDB_memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
00408                                 goto out;
00409                         lp = NULL;
00410                 }
00411 
00412                 /* If the right child is wrong, update it. */
00413                 if (rp == NULL && (ret = CDB_memp_fget(mpf,
00414                     &argp->right, DB_MPOOL_CREATE, &rp)) != 0) {
00415                         (void)CDB___db_pgerr(file_dbp, argp->right);
00416                         rp = NULL;
00417                         goto out;
00418                 }
00419                 if (r_update) {
00420                         memcpy(rp, _rp, file_dbp->pgsize);
00421                         rp->lsn = *lsnp;
00422                         if ((ret = CDB_memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
00423                                 goto out;
00424                         rp = NULL;
00425                 }
00426 
00427                 /*
00428                  * If the parent page is wrong, update it.  This is of interest
00429                  * only if it was a root split, since root splits create parent
00430                  * pages.  All other splits modify a parent page, but those are
00431                  * separately logged and recovered.
00432                  */
00433                 if (rootsplit && p_update) {
00434                         if (IS_BTREE_PAGE(sp)) {
00435                                 ptype = P_IBTREE;
00436                                 rc = argp->opflags & SPL_NRECS ? 1 : 0;
00437                         } else {
00438                                 ptype = P_IRECNO;
00439                                 rc = 1;
00440                         }
00441 
00442                         P_INIT(pp, file_dbp->pgsize, root_pgno,
00443                             PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype, 0);
00444                         RE_NREC_SET(pp,
00445                             rc ? CDB___bam_total(_lp) + CDB___bam_total(_rp) : 0);
00446 
00447                         pp->lsn = *lsnp;
00448                         if ((ret = CDB_memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
00449                                 goto out;
00450                         pp = NULL;
00451                 }
00452 
00453 check_next:     /*
00454                  * Finally, redo the next-page link if necessary.  This is of
00455                  * interest only if it wasn't a root split -- inserting a new
00456                  * page in the tree requires that any following page have its
00457                  * previous-page pointer updated to our new page.  The next
00458                  * page must exist because we're redoing the operation.
00459                  */
00460                 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
00461                         if ((ret = CDB_memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
00462                                 (void)CDB___db_pgerr(file_dbp, argp->npgno);
00463                                 np = NULL;
00464                                 goto out;
00465                         }
00466                         cmp = CDB_log_compare(&LSN(np), &argp->nlsn);
00467                         CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn);
00468                         if (cmp == 0) {
00469                                 PREV_PGNO(np) = argp->right;
00470                                 np->lsn = *lsnp;
00471                                 if ((ret =
00472                                     CDB_memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0)
00473                                         goto out;
00474                                 np = NULL;
00475                         }
00476                 }
00477         } else {
00478                 /*
00479                  * If the split page is wrong, replace its contents with the
00480                  * logged page contents.  If the page doesn't exist, it means
00481                  * that the create of the page never happened, nor did any of
00482                  * the adds onto the page that caused the split, and there's
00483                  * really no undo-ing to be done.
00484                  */
00485                 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pp)) != 0) {
00486                         pp = NULL;
00487                         goto lrundo;
00488                 }
00489                 if (CDB_log_compare(lsnp, &LSN(pp)) == 0) {
00490                         memcpy(pp, argp->pg.data, argp->pg.size);
00491                         if ((ret = CDB_memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
00492                                 goto out;
00493                         pp = NULL;
00494                 }
00495 
00496                 /*
00497                  * If it's a root split and the left child ever existed, update
00498                  * its LSN.  (If it's not a root split, we've updated the left
00499                  * page already -- it's the same as the split page.) If the
00500                  * right child ever existed, root split or not, update its LSN.
00501                  * The undo of the page allocation(s) will restore them to the
00502                  * free list.
00503                  */
00504 lrundo:         if ((rootsplit && lp != NULL) || rp != NULL) {
00505                         if (rootsplit && lp != NULL &&
00506                             CDB_log_compare(lsnp, &LSN(lp)) == 0) {
00507                                 lp->lsn = argp->llsn;
00508                                 if ((ret =
00509                                     CDB_memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
00510                                         goto out;
00511                                 lp = NULL;
00512                         }
00513                         if (rp != NULL &&
00514                             CDB_log_compare(lsnp, &LSN(rp)) == 0) {
00515                                 rp->lsn = argp->rlsn;
00516                                 if ((ret =
00517                                     CDB_memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
00518                                         goto out;
00519                                 rp = NULL;
00520                         }
00521                 }
00522 
00523                 /*
00524                  * Finally, undo the next-page link if necessary.  This is of
00525                  * interest only if it wasn't a root split -- inserting a new
00526                  * page in the tree requires that any following page have its
00527                  * previous-page pointer updated to our new page.  Since it's
00528                  * possible that the next-page never existed, we ignore it as
00529                  * if there's nothing to undo.
00530                  */
00531                 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
00532                         if ((ret = CDB_memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
00533                                 np = NULL;
00534                                 goto done;
00535                         }
00536                         if (CDB_log_compare(lsnp, &LSN(np)) == 0) {
00537                                 PREV_PGNO(np) = argp->left;
00538                                 np->lsn = argp->nlsn;
00539                                 if (CDB_memp_fput(mpf, np, DB_MPOOL_DIRTY))
00540                                         goto out;
00541                                 np = NULL;
00542                         }
00543                 }
00544         }
00545 
00546 done:   *lsnp = argp->prev_lsn;
00547         ret = 0;
00548 
00549 out:    /* Free any pages that weren't dirtied. */
00550         if (pp != NULL && (t_ret = CDB_memp_fput(mpf, pp, 0)) != 0 && ret == 0)
00551                 ret = t_ret;
00552         if (lp != NULL && (t_ret = CDB_memp_fput(mpf, lp, 0)) != 0 && ret == 0)
00553                 ret = t_ret;
00554         if (np != NULL && (t_ret = CDB_memp_fput(mpf, np, 0)) != 0 && ret == 0)
00555                 ret = t_ret;
00556         if (rp != NULL && (t_ret = CDB_memp_fput(mpf, rp, 0)) != 0 && ret == 0)
00557                 ret = t_ret;
00558 
00559         /* Free any allocated space. */
00560         if (_lp != NULL)
00561                 CDB___os_free(_lp, file_dbp->pgsize);
00562         if (_rp != NULL)
00563                 CDB___os_free(_rp, file_dbp->pgsize);
00564         if (sp != NULL)
00565                 CDB___os_free(sp, argp->pg.size);
00566 
00567         REC_CLOSE;
00568 }
00569 
00570 /*
00571  * CDB___bam_rsplit_recover --
00572  *      Recovery function for a reverse split.
00573  *
00574  * PUBLIC: int CDB___bam_rsplit_recover
00575  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00576  */
00577 int
00578 CDB___bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
00579         DB_ENV *dbenv;
00580         DBT *dbtp;
00581         DB_LSN *lsnp;
00582         db_recops op;
00583         void *info;
00584 {
00585         __bam_rsplit_args *argp;
00586         DB *file_dbp;
00587         DBC *dbc;
00588         DB_LSN copy_lsn;
00589         DB_MPOOLFILE *mpf;
00590         PAGE *pagep;
00591         db_pgno_t pgno, root_pgno;
00592         int cmp_n, cmp_p, modified, ret;
00593 
00594         COMPQUIET(info, NULL);
00595         REC_PRINT(CDB___bam_rsplit_print);
00596         REC_INTRO(CDB___bam_rsplit_read, 1);
00597 
00598         /* Fix the root page. */
00599         pgno = root_pgno = argp->root_pgno;
00600         if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
00601                 /* The root page must always exist if we are going forward. */
00602                 if (DB_REDO(op)) {
00603                         CDB___db_pgerr(file_dbp, pgno);
00604                         goto out;
00605                 }
00606                 /* This must be the root of an OPD tree. */
00607                 DB_ASSERT(root_pgno !=
00608                     ((BTREE *)file_dbp->bt_internal)->bt_root);
00609                 ret = 0;
00610                 goto done;
00611         }
00612         modified = 0;
00613         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00614         cmp_p = CDB_log_compare(&LSN(pagep), &argp->rootlsn);
00615         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->rootlsn);
00616         if (cmp_p == 0 && DB_REDO(op)) {
00617                 /* Need to redo update described. */
00618                 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
00619                 pagep->pgno = root_pgno;
00620                 pagep->lsn = *lsnp;
00621                 modified = 1;
00622         } else if (cmp_n == 0 && DB_UNDO(op)) {
00623                 /* Need to undo update described. */
00624                 P_INIT(pagep, file_dbp->pgsize, root_pgno,
00625                     argp->nrec, PGNO_INVALID, pagep->level + 1,
00626                     IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO,
00627                        TAGS(pagep));
00628                 if ((ret = CDB___db_pitem(dbc, pagep, 0,
00629                     argp->rootent.size, &argp->rootent, NULL)) != 0)
00630                         goto out;
00631                 pagep->lsn = argp->rootlsn;
00632                 modified = 1;
00633         }
00634         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00635                 goto out;
00636 
00637         /*
00638          * Fix the page copied over the root page.  It's possible that the
00639          * page never made it to disk, so if we're undo-ing and the page
00640          * doesn't exist, it's okay and there's nothing further to do.
00641          */
00642         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00643                 if (DB_UNDO(op))
00644                         goto done;
00645                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00646                 goto out;
00647         }
00648         modified = 0;
00649         CDB___ua_memcpy(&copy_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
00650         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00651         cmp_p = CDB_log_compare(&LSN(pagep), &copy_lsn);
00652         CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
00653         if (cmp_p == 0 && DB_REDO(op)) {
00654                 /* Need to redo update described. */
00655                 pagep->lsn = *lsnp;
00656                 modified = 1;
00657         } else if (cmp_n == 0 && DB_UNDO(op)) {
00658                 /* Need to undo update described. */
00659                 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
00660                 modified = 1;
00661         }
00662         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00663                 goto out;
00664 
00665 done:   *lsnp = argp->prev_lsn;
00666         ret = 0;
00667 
00668 out:    REC_CLOSE;
00669 }
00670 
00671 /*
00672  * CDB___bam_adj_recover --
00673  *      Recovery function for adj.
00674  *
00675  * PUBLIC: int CDB___bam_adj_recover
00676  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00677  */
00678 int
00679 CDB___bam_adj_recover(dbenv, dbtp, lsnp, op, info)
00680         DB_ENV *dbenv;
00681         DBT *dbtp;
00682         DB_LSN *lsnp;
00683         db_recops op;
00684         void *info;
00685 {
00686         __bam_adj_args *argp;
00687         DB *file_dbp;
00688         DBC *dbc;
00689         DB_MPOOLFILE *mpf;
00690         PAGE *pagep;
00691         int cmp_n, cmp_p, modified, ret;
00692 
00693         COMPQUIET(info, NULL);
00694         REC_PRINT(CDB___bam_adj_print);
00695         REC_INTRO(CDB___bam_adj_read, 1);
00696 
00697         /* Get the page; if it never existed and we're undoing, we're done. */
00698         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00699                 if (DB_UNDO(op))
00700                         goto done;
00701                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00702                 goto out;
00703         }
00704 
00705         modified = 0;
00706         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00707         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00708         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00709         if (cmp_p == 0 && DB_REDO(op)) {
00710                 /* Need to redo update described. */
00711                 if ((ret = CDB___bam_adjindx(dbc,
00712                     pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
00713                         goto err;
00714 
00715                 LSN(pagep) = *lsnp;
00716                 modified = 1;
00717         } else if (cmp_n == 0 && DB_UNDO(op)) {
00718                 /* Need to undo update described. */
00719                 if ((ret = CDB___bam_adjindx(dbc,
00720                     pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
00721                         goto err;
00722 
00723                 LSN(pagep) = argp->lsn;
00724                 modified = 1;
00725         }
00726         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00727                 goto out;
00728 
00729 done:   *lsnp = argp->prev_lsn;
00730         ret = 0;
00731 
00732         if (0) {
00733 err:            (void)CDB_memp_fput(mpf, pagep, 0);
00734         }
00735 out:    REC_CLOSE;
00736 }
00737 
00738 /*
00739  * CDB___bam_cadjust_recover --
00740  *      Recovery function for the adjust of a count change in an internal
00741  *      page.
00742  *
00743  * PUBLIC: int CDB___bam_cadjust_recover
00744  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00745  */
00746 int
00747 CDB___bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
00748         DB_ENV *dbenv;
00749         DBT *dbtp;
00750         DB_LSN *lsnp;
00751         db_recops op;
00752         void *info;
00753 {
00754         __bam_cadjust_args *argp;
00755         DB *file_dbp;
00756         DBC *dbc;
00757         DB_MPOOLFILE *mpf;
00758         PAGE *pagep;
00759         int cmp_n, cmp_p, modified, ret;
00760 
00761         COMPQUIET(info, NULL);
00762         REC_PRINT(CDB___bam_cadjust_print);
00763         REC_INTRO(CDB___bam_cadjust_read, 1);
00764 
00765         /* Get the page; if it never existed and we're undoing, we're done. */
00766         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00767                 if (DB_UNDO(op))
00768                         goto done;
00769                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00770                 goto out;
00771         }
00772 
00773         modified = 0;
00774         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00775         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00776         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00777         if (cmp_p == 0 && DB_REDO(op)) {
00778                 /* Need to redo update described. */
00779                 if (IS_BTREE_PAGE(pagep)) {
00780                         GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
00781                         if (argp->opflags & CAD_UPDATEROOT)
00782                                 RE_NREC_ADJ(pagep, argp->adjust);
00783                 } else {
00784                         GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
00785                         if (argp->opflags & CAD_UPDATEROOT)
00786                                 RE_NREC_ADJ(pagep, argp->adjust);
00787                 }
00788 
00789                 LSN(pagep) = *lsnp;
00790                 modified = 1;
00791         } else if (cmp_n == 0 && DB_UNDO(op)) {
00792                 /* Need to undo update described. */
00793                 if (IS_BTREE_PAGE(pagep)) {
00794                         GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
00795                         if (argp->opflags & CAD_UPDATEROOT)
00796                                 RE_NREC_ADJ(pagep, argp->adjust);
00797                 } else {
00798                         GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
00799                         if (argp->opflags & CAD_UPDATEROOT)
00800                                 RE_NREC_ADJ(pagep, -(argp->adjust));
00801                 }
00802                 LSN(pagep) = argp->lsn;
00803                 modified = 1;
00804         }
00805         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00806                 goto out;
00807 
00808 done:   *lsnp = argp->prev_lsn;
00809         ret = 0;
00810 
00811 out:    REC_CLOSE;
00812 }
00813 
00814 /*
00815  * CDB___bam_cdel_recover --
00816  *      Recovery function for the intent-to-delete of a cursor record.
00817  *
00818  * PUBLIC: int CDB___bam_cdel_recover
00819  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00820  */
00821 int
00822 CDB___bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
00823         DB_ENV *dbenv;
00824         DBT *dbtp;
00825         DB_LSN *lsnp;
00826         db_recops op;
00827         void *info;
00828 {
00829         __bam_cdel_args *argp;
00830         DB *file_dbp;
00831         DBC *dbc;
00832         DB_MPOOLFILE *mpf;
00833         PAGE *pagep;
00834         u_int32_t indx;
00835         int cmp_n, cmp_p, modified, ret;
00836 
00837         COMPQUIET(info, NULL);
00838         REC_PRINT(CDB___bam_cdel_print);
00839         REC_INTRO(CDB___bam_cdel_read, 1);
00840 
00841         /* Get the page; if it never existed and we're undoing, we're done. */
00842         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00843                 if (DB_UNDO(op))
00844                         goto done;
00845                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00846                 goto out;
00847         }
00848 
00849         modified = 0;
00850         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00851         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00852         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00853         if (cmp_p == 0 && DB_REDO(op)) {
00854                 /* Need to redo update described. */
00855                 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
00856                 B_DSET(GET_BKEYDATA(pagep, indx)->type);
00857 
00858                 LSN(pagep) = *lsnp;
00859                 modified = 1;
00860         } else if (cmp_n == 0 && DB_UNDO(op)) {
00861                 /* Need to undo update described. */
00862                 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
00863                 B_DCLR(GET_BKEYDATA(pagep, indx)->type);
00864 
00865                 LSN(pagep) = argp->lsn;
00866                 modified = 1;
00867         }
00868         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00869                 goto out;
00870 
00871 done:   *lsnp = argp->prev_lsn;
00872         ret = 0;
00873 
00874 out:    REC_CLOSE;
00875 }
00876 
00877 /*
00878  * CDB___bam_repl_recover --
00879  *      Recovery function for page item replacement.
00880  *
00881  * PUBLIC: int CDB___bam_repl_recover
00882  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00883  */
00884 int
00885 CDB___bam_repl_recover(dbenv, dbtp, lsnp, op, info)
00886         DB_ENV *dbenv;
00887         DBT *dbtp;
00888         DB_LSN *lsnp;
00889         db_recops op;
00890         void *info;
00891 {
00892         __bam_repl_args *argp;
00893         BKEYDATA *bk;
00894         DB *file_dbp;
00895         DBC *dbc;
00896         DBT dbt;
00897         DB_MPOOLFILE *mpf;
00898         PAGE *pagep;
00899         int cmp_n, cmp_p, modified, ret;
00900         u_int8_t *p;
00901 
00902         COMPQUIET(info, NULL);
00903         REC_PRINT(CDB___bam_repl_print);
00904         REC_INTRO(CDB___bam_repl_read, 1);
00905 
00906         /* Get the page; if it never existed and we're undoing, we're done. */
00907         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00908                 if (DB_UNDO(op))
00909                         goto done;
00910                 (void)CDB___db_pgerr(file_dbp, argp->pgno);
00911                 goto out;
00912         }
00913         bk = GET_BKEYDATA(pagep, argp->indx);
00914 
00915         modified = 0;
00916         cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00917         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00918         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00919         if (cmp_p == 0 && DB_REDO(op)) {
00920                 /*
00921                  * Need to redo update described.
00922                  *
00923                  * Re-build the replacement item.
00924                  */
00925                 memset(&dbt, 0, sizeof(dbt));
00926                 dbt.size = argp->prefix + argp->suffix + argp->repl.size;
00927                 if ((ret = CDB___os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0)
00928                         goto err;
00929                 p = dbt.data;
00930                 memcpy(p, bk->data, argp->prefix);
00931                 p += argp->prefix;
00932                 memcpy(p, argp->repl.data, argp->repl.size);
00933                 p += argp->repl.size;
00934                 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
00935 
00936                 ret = CDB___bam_ritem(dbc, pagep, argp->indx, &dbt);
00937                 CDB___os_free(dbt.data, dbt.size);
00938                 if (ret != 0)
00939                         goto err;
00940 
00941                 LSN(pagep) = *lsnp;
00942                 modified = 1;
00943         } else if (cmp_n == 0 && DB_UNDO(op)) {
00944                 /*
00945                  * Need to undo update described.
00946                  *
00947                  * Re-build the original item.
00948                  */
00949                 memset(&dbt, 0, sizeof(dbt));
00950                 dbt.size = argp->prefix + argp->suffix + argp->orig.size;
00951                 if ((ret = CDB___os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0)
00952                         goto err;
00953                 p = dbt.data;
00954                 memcpy(p, bk->data, argp->prefix);
00955                 p += argp->prefix;
00956                 memcpy(p, argp->orig.data, argp->orig.size);
00957                 p += argp->orig.size;
00958                 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
00959 
00960                 ret = CDB___bam_ritem(dbc, pagep, argp->indx, &dbt);
00961                 CDB___os_free(dbt.data, dbt.size);
00962                 if (ret != 0)
00963                         goto err;
00964 
00965                 /* Reset the deleted flag, if necessary. */
00966                 if (argp->isdeleted)
00967                         B_DSET(GET_BKEYDATA(pagep, argp->indx)->type);
00968 
00969                 LSN(pagep) = argp->lsn;
00970                 modified = 1;
00971         }
00972         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00973                 goto out;
00974 
00975 done:   *lsnp = argp->prev_lsn;
00976         ret = 0;
00977 
00978         if (0) {
00979 err:            (void)CDB_memp_fput(mpf, pagep, 0);
00980         }
00981 out:    REC_CLOSE;
00982 }
00983 
00984 /*
00985  * CDB___bam_root_recover --
00986  *      Recovery function for setting the root page on the meta-data page.
00987  *
00988  * PUBLIC: int CDB___bam_root_recover
00989  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00990  */
00991 int
00992 CDB___bam_root_recover(dbenv, dbtp, lsnp, op, info)
00993         DB_ENV *dbenv;
00994         DBT *dbtp;
00995         DB_LSN *lsnp;
00996         db_recops op;
00997         void *info;
00998 {
00999         __bam_root_args *argp;
01000         BTMETA *meta;
01001         DB *file_dbp;
01002         DBC *dbc;
01003         DB_MPOOLFILE *mpf;
01004         int cmp_n, cmp_p, modified, ret;
01005 
01006         COMPQUIET(info, NULL);
01007         REC_PRINT(CDB___bam_root_print);
01008         REC_INTRO(CDB___bam_root_read, 0);
01009 
01010         if ((ret = CDB_memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
01011                 /* The metadata page must always exist on redo. */
01012                 if (DB_REDO(op)) {
01013                         (void)CDB___db_pgerr(file_dbp, argp->meta_pgno);
01014                         goto out;
01015                 } else
01016                         goto done;
01017         }
01018 
01019         modified = 0;
01020         cmp_n = CDB_log_compare(lsnp, &LSN(meta));
01021         cmp_p = CDB_log_compare(&LSN(meta), &argp->meta_lsn);
01022         CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
01023         if (cmp_p == 0 && DB_REDO(op)) {
01024                 /* Need to redo update described. */
01025                 meta->root = argp->root_pgno;
01026                 meta->dbmeta.lsn = *lsnp;
01027                 ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root;
01028                 modified = 1;
01029         } else if (cmp_n == 0 && DB_UNDO(op)) {
01030                 /* Nothing to undo except lsn. */
01031                 meta->dbmeta.lsn = argp->meta_lsn;
01032                 modified = 1;
01033         }
01034         if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
01035                 goto out;
01036 
01037 done:   *lsnp = argp->prev_lsn;
01038         ret = 0;
01039 
01040 out:    REC_CLOSE;
01041 }

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