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

hash_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 /*
00008  * Copyright (c) 1995, 1996
00009  *      Margo Seltzer.  All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1995, 1996
00013  *      The President and Fellows of Harvard University.  All rights reserved.
00014  *
00015  * This code is derived from software contributed to Berkeley by
00016  * Margo Seltzer.
00017  *
00018  * Redistribution and use in source and binary forms, with or without
00019  * modification, are permitted provided that the following conditions
00020  * are met:
00021  * 1. Redistributions of source code must retain the above copyright
00022  *    notice, this list of conditions and the following disclaimer.
00023  * 2. Redistributions in binary form must reproduce the above copyright
00024  *    notice, this list of conditions and the following disclaimer in the
00025  *    documentation and/or other materials provided with the distribution.
00026  * 3. Neither the name of the University nor the names of its contributors
00027  *    may be used to endorse or promote products derived from this software
00028  *    without specific prior written permission.
00029  *
00030  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00031  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00034  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00035  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00036  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00037  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00038  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00039  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00040  * SUCH DAMAGE.
00041  *
00042  * $Id: hash_rec.c,v 12.7 2005/09/28 17:44:52 margo Exp $
00043  */
00044 
00045 #include "db_config.h"
00046 
00047 #ifndef NO_SYSTEM_INCLUDES
00048 #include <sys/types.h>
00049 
00050 #include <string.h>
00051 #endif
00052 
00053 #include "db_int.h"
00054 #include "dbinc/db_page.h"
00055 #include "dbinc/db_shash.h"
00056 #include "dbinc/btree.h"
00057 #include "dbinc/hash.h"
00058 #include "dbinc/log.h"
00059 #include "dbinc/mp.h"
00060 
00061 static int __ham_alloc_pages __P((DB *, __ham_groupalloc_args *, DB_LSN *));
00062 
00063 /*
00064  * __ham_insdel_recover --
00065  *
00066  * PUBLIC: int __ham_insdel_recover
00067  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00068  */
00069 int
00070 __ham_insdel_recover(dbenv, dbtp, lsnp, op, info)
00071         DB_ENV *dbenv;
00072         DBT *dbtp;
00073         DB_LSN *lsnp;
00074         db_recops op;
00075         void *info;
00076 {
00077         __ham_insdel_args *argp;
00078         DB *file_dbp;
00079         DBC *dbc;
00080         DB_MPOOLFILE *mpf;
00081         PAGE *pagep;
00082         u_int32_t flags, opcode;
00083         int cmp_n, cmp_p, ret, type;
00084 
00085         pagep = NULL;
00086         COMPQUIET(info, NULL);
00087 
00088         REC_PRINT(__ham_insdel_print);
00089         REC_INTRO(__ham_insdel_read, 1, 0);
00090 
00091         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00092                 if (DB_UNDO(op)) {
00093                         if (ret == DB_PAGE_NOTFOUND)
00094                                 goto done;
00095                         else {
00096                                 ret = __db_pgerr(file_dbp, argp->pgno, ret);
00097                                 goto out;
00098                         }
00099                 }
00100 #ifdef HAVE_FTRUNCATE
00101                 /* If the page is not here then it was later truncated. */
00102                 if (!IS_ZERO_LSN(argp->pagelsn))
00103                         goto done;
00104 #endif
00105                 /*
00106                  * This page was created by a group allocation and
00107                  * the file may not have been extend yet.
00108                  * Create the page if necessary.
00109                  */
00110                 if ((ret = __memp_fget(mpf,
00111                      &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00112                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00113                         goto out;
00114                 }
00115         }
00116 
00117         cmp_n = log_compare(lsnp, &LSN(pagep));
00118         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00119         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00120         /*
00121          * Two possible things going on:
00122          * redo a delete/undo a put: delete the item from the page.
00123          * redo a put/undo a delete: add the item to the page.
00124          * If we are undoing a delete, then the information logged is the
00125          * entire entry off the page, not just the data of a dbt.  In
00126          * this case, we want to copy it back onto the page verbatim.
00127          * We do this by calling __putitem with the type H_OFFPAGE instead
00128          * of H_KEYDATA.
00129          */
00130 
00131         opcode = OPCODE_OF(argp->opcode);
00132         flags = 0;
00133         if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
00134             (opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
00135                 /*
00136                  * Need to redo a PUT or undo a delete.  If we are undoing a
00137                  * delete, we've got to restore the item back to its original
00138                  * position.  That's a royal pain in the butt (because we do
00139                  * not store item lengths on the page), but there's no choice.
00140                  */
00141                 if (opcode != DELPAIR ||
00142                     argp->ndx == (u_int32_t)NUM_ENT(pagep)) {
00143                         __ham_putitem(file_dbp, pagep, &argp->key,
00144                             DB_UNDO(op) || PAIR_ISKEYBIG(argp->opcode) ?
00145                             H_OFFPAGE : H_KEYDATA);
00146 
00147                         if (PAIR_ISDATADUP(argp->opcode))
00148                                 type = H_DUPLICATE;
00149                         else if (DB_UNDO(op) || PAIR_ISDATABIG(argp->opcode))
00150                                 type = H_OFFPAGE;
00151                         else
00152                                 type = H_KEYDATA;
00153                         __ham_putitem(file_dbp, pagep, &argp->data, type);
00154                 } else
00155                         __ham_reputpair(file_dbp, pagep,
00156                             argp->ndx, &argp->key, &argp->data);
00157 
00158                 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00159                 flags = DB_MPOOL_DIRTY;
00160 
00161         } else if ((opcode == DELPAIR && cmp_p == 0 && DB_REDO(op)) ||
00162             (opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) {
00163                 /* Need to undo a put or redo a delete. */
00164                 __ham_dpair(file_dbp, pagep, argp->ndx);
00165                 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00166                 flags = DB_MPOOL_DIRTY;
00167         }
00168 
00169         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00170                 goto out;
00171         pagep = NULL;
00172 
00173         /* Return the previous LSN. */
00174 done:   *lsnp = argp->prev_lsn;
00175         ret = 0;
00176 
00177 out:    if (pagep != NULL)
00178                 (void)__memp_fput(mpf, pagep, 0);
00179         REC_CLOSE;
00180 }
00181 
00182 /*
00183  * __ham_newpage_recover --
00184  *      This log message is used when we add/remove overflow pages.  This
00185  *      message takes care of the pointer chains, not the data on the pages.
00186  *
00187  * PUBLIC: int __ham_newpage_recover
00188  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00189  */
00190 int
00191 __ham_newpage_recover(dbenv, dbtp, lsnp, op, info)
00192         DB_ENV *dbenv;
00193         DBT *dbtp;
00194         DB_LSN *lsnp;
00195         db_recops op;
00196         void *info;
00197 {
00198         __ham_newpage_args *argp;
00199         DB *file_dbp;
00200         DBC *dbc;
00201         DB_MPOOLFILE *mpf;
00202         PAGE *pagep;
00203         u_int32_t flags;
00204         int cmp_n, cmp_p, ret;
00205 
00206         pagep = NULL;
00207         COMPQUIET(info, NULL);
00208 
00209         REC_PRINT(__ham_newpage_print);
00210         REC_INTRO(__ham_newpage_read, 1, 0);
00211 
00212         REC_FGET(mpf, argp->new_pgno, &pagep, ppage);
00213 
00214         /*
00215          * There are potentially three pages we need to check: the one
00216          * that we created/deleted, the one before it and the one after
00217          * it.
00218          */
00219 
00220         cmp_n = log_compare(lsnp, &LSN(pagep));
00221         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00222         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00223 
00224         flags = 0;
00225         if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00226             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00227                 /* Redo a create new page or undo a delete new page. */
00228                 P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
00229                     argp->prev_pgno, argp->next_pgno, 0, P_HASH);
00230                 flags = DB_MPOOL_DIRTY;
00231         } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
00232             (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00233                 /*
00234                  * Redo a delete or undo a create new page.  All we
00235                  * really need to do is change the LSN.
00236                  */
00237                 flags = DB_MPOOL_DIRTY;
00238         }
00239 
00240         if (flags)
00241                 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00242 
00243         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00244                 goto out;
00245         pagep = NULL;
00246 
00247         /* Now do the prev page. */
00248 ppage:  if (argp->prev_pgno != PGNO_INVALID) {
00249                 REC_FGET(mpf, argp->prev_pgno, &pagep, npage);
00250 
00251                 cmp_n = log_compare(lsnp, &LSN(pagep));
00252                 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
00253                 CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->prevlsn);
00254                 flags = 0;
00255 
00256                 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00257                     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00258                         /* Redo a create new page or undo a delete new page. */
00259                         pagep->next_pgno = argp->new_pgno;
00260                         flags = DB_MPOOL_DIRTY;
00261                 } else if ((cmp_p == 0 &&
00262                     DB_REDO(op) && argp->opcode == DELOVFL) ||
00263                     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00264                         /* Redo a delete or undo a create new page. */
00265                         pagep->next_pgno = argp->next_pgno;
00266                         flags = DB_MPOOL_DIRTY;
00267                 }
00268 
00269                 if (flags)
00270                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
00271 
00272                 if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00273                         goto out;
00274                 pagep = NULL;
00275         }
00276 
00277         /* Now time to do the next page */
00278 npage:  if (argp->next_pgno != PGNO_INVALID) {
00279                 REC_FGET(mpf, argp->next_pgno, &pagep, done);
00280 
00281                 cmp_n = log_compare(lsnp, &LSN(pagep));
00282                 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
00283                 CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->nextlsn);
00284                 flags = 0;
00285 
00286                 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00287                     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00288                         /* Redo a create new page or undo a delete new page. */
00289                         pagep->prev_pgno = argp->new_pgno;
00290                         flags = DB_MPOOL_DIRTY;
00291                 } else if ((cmp_p == 0 &&
00292                     DB_REDO(op) && argp->opcode == DELOVFL) ||
00293                     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00294                         /* Redo a delete or undo a create new page. */
00295                         pagep->prev_pgno = argp->prev_pgno;
00296                         flags = DB_MPOOL_DIRTY;
00297                 }
00298 
00299                 if (flags)
00300                         LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
00301 
00302                 if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00303                         goto out;
00304                 pagep = NULL;
00305         }
00306 done:   *lsnp = argp->prev_lsn;
00307         ret = 0;
00308 
00309 out:    if (pagep != NULL)
00310                 (void)__memp_fput(mpf, pagep, 0);
00311         REC_CLOSE;
00312 }
00313 
00314 /*
00315  * __ham_replace_recover --
00316  *      This log message refers to partial puts that are local to a single
00317  *      page.  You can think of them as special cases of the more general
00318  *      insdel log message.
00319  *
00320  * PUBLIC: int __ham_replace_recover
00321  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00322  */
00323 int
00324 __ham_replace_recover(dbenv, dbtp, lsnp, op, info)
00325         DB_ENV *dbenv;
00326         DBT *dbtp;
00327         DB_LSN *lsnp;
00328         db_recops op;
00329         void *info;
00330 {
00331         __ham_replace_args *argp;
00332         DB *file_dbp;
00333         DBC *dbc;
00334         DB_MPOOLFILE *mpf;
00335         DBT dbt;
00336         PAGE *pagep;
00337         u_int32_t flags;
00338         u_int32_t change;
00339         int cmp_n, cmp_p, is_plus, ret;
00340         u_int8_t *hk;
00341 
00342         pagep = NULL;
00343         COMPQUIET(info, NULL);
00344 
00345         REC_PRINT(__ham_replace_print);
00346         REC_INTRO(__ham_replace_read, 1, 0);
00347 
00348         REC_FGET(mpf, argp->pgno, &pagep, done);
00349 
00350         cmp_n = log_compare(lsnp, &LSN(pagep));
00351         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00352         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00353 
00354         memset(&dbt, 0, sizeof(dbt));
00355         flags = 0;
00356 
00357         /*
00358          * Before we know the direction of the transformation we will
00359          * determine the size differential; then once we know if we are
00360          * redoing or undoing, we'll adjust the sign (is_plus) appropriately.
00361          */
00362         if (argp->newitem.size > argp->olditem.size) {
00363                 change = argp->newitem.size - argp->olditem.size;
00364                 is_plus = 1;
00365         } else {
00366                 change = argp->olditem.size - argp->newitem.size;
00367                 is_plus = 0;
00368         }
00369         if (cmp_p == 0 && DB_REDO(op)) {
00370                 /* Reapply the change as specified. */
00371                 dbt.data = argp->newitem.data;
00372                 dbt.size = argp->newitem.size;
00373                 LSN(pagep) = *lsnp;
00374                 /*
00375                  * The is_plus flag is set properly to reflect
00376                  * newitem.size - olditem.size.
00377                  */
00378                 flags = DB_MPOOL_DIRTY;
00379         } else if (cmp_n == 0 && DB_UNDO(op)) {
00380                 /* Undo the already applied change. */
00381                 dbt.data = argp->olditem.data;
00382                 dbt.size = argp->olditem.size;
00383                 /*
00384                  * Invert is_plus to reflect sign of
00385                  * olditem.size - newitem.size.
00386                  */
00387                 is_plus = !is_plus;
00388                 LSN(pagep) = argp->pagelsn;
00389                 flags = DB_MPOOL_DIRTY;
00390         }
00391 
00392         if (flags) {
00393                 __ham_onpage_replace(file_dbp, pagep,
00394                     argp->ndx, argp->off, change, is_plus, &dbt);
00395                 if (argp->makedup) {
00396                         hk = P_ENTRY(file_dbp, pagep, argp->ndx);
00397                         if (DB_REDO(op))
00398                                 HPAGE_PTYPE(hk) = H_DUPLICATE;
00399                         else
00400                                 HPAGE_PTYPE(hk) = H_KEYDATA;
00401                 }
00402         }
00403 
00404         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00405                 goto out;
00406         pagep = NULL;
00407 
00408 done:   *lsnp = argp->prev_lsn;
00409         ret = 0;
00410 
00411 out:    if (pagep != NULL)
00412                 (void)__memp_fput(mpf, pagep, 0);
00413         REC_CLOSE;
00414 }
00415 
00416 /*
00417  * __ham_splitdata_recover --
00418  *
00419  * PUBLIC: int __ham_splitdata_recover
00420  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00421  */
00422 int
00423 __ham_splitdata_recover(dbenv, dbtp, lsnp, op, info)
00424         DB_ENV *dbenv;
00425         DBT *dbtp;
00426         DB_LSN *lsnp;
00427         db_recops op;
00428         void *info;
00429 {
00430         __ham_splitdata_args *argp;
00431         DB *file_dbp;
00432         DBC *dbc;
00433         DB_MPOOLFILE *mpf;
00434         PAGE *pagep;
00435         u_int32_t flags;
00436         int cmp_n, cmp_p, ret;
00437 
00438         pagep = NULL;
00439         COMPQUIET(info, NULL);
00440 
00441         REC_PRINT(__ham_splitdata_print);
00442         REC_INTRO(__ham_splitdata_read, 1, 0);
00443 
00444         if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00445                 if (DB_UNDO(op)) {
00446                         if (ret == DB_PAGE_NOTFOUND)
00447                                 goto done;
00448                         else {
00449                                 ret = __db_pgerr(file_dbp, argp->pgno, ret);
00450                                 goto out;
00451                         }
00452                 }
00453 #ifdef HAVE_FTRUNCATE
00454                 /* If the page is not here then it was later truncated. */
00455                 if (!IS_ZERO_LSN(argp->pagelsn))
00456                         goto done;
00457 #endif
00458                 /*
00459                  * This page was created by a group allocation and
00460                  * the file may not have been extend yet.
00461                  * Create the page if necessary.
00462                  */
00463                 if ((ret = __memp_fget(mpf,
00464                      &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00465                         ret = __db_pgerr(file_dbp, argp->pgno, ret);
00466                         goto out;
00467                 }
00468         }
00469 
00470         cmp_n = log_compare(lsnp, &LSN(pagep));
00471         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00472         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00473 
00474         /*
00475          * There are two types of log messages here, one for the old page
00476          * and one for the new pages created.  The original image in the
00477          * SPLITOLD record is used for undo.  The image in the SPLITNEW
00478          * is used for redo.  We should never have a case where there is
00479          * a redo operation and the SPLITOLD record is on disk, but not
00480          * the SPLITNEW record.  Therefore, we only have work to do when
00481          * redo NEW messages and undo OLD messages, but we have to update
00482          * LSNs in both cases.
00483          */
00484         flags = 0;
00485         if (cmp_p == 0 && DB_REDO(op)) {
00486                 if (argp->opcode == SPLITNEW)
00487                         /* Need to redo the split described. */
00488                         memcpy(pagep, argp->pageimage.data,
00489                             argp->pageimage.size);
00490                 LSN(pagep) = *lsnp;
00491                 flags = DB_MPOOL_DIRTY;
00492         } else if (cmp_n == 0 && DB_UNDO(op)) {
00493                 if (argp->opcode == SPLITOLD) {
00494                         /* Put back the old image. */
00495                         memcpy(pagep, argp->pageimage.data,
00496                             argp->pageimage.size);
00497                 } else
00498                         P_INIT(pagep, file_dbp->pgsize, argp->pgno,
00499                             PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
00500                 LSN(pagep) = argp->pagelsn;
00501                 flags = DB_MPOOL_DIRTY;
00502         }
00503         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00504                 goto out;
00505         pagep = NULL;
00506 
00507 done:   *lsnp = argp->prev_lsn;
00508         ret = 0;
00509 
00510 out:    if (pagep != NULL)
00511                 (void)__memp_fput(mpf, pagep, 0);
00512         REC_CLOSE;
00513 }
00514 
00515 /*
00516  * __ham_copypage_recover --
00517  *      Recovery function for copypage.
00518  *
00519  * PUBLIC: int __ham_copypage_recover
00520  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00521  */
00522 int
00523 __ham_copypage_recover(dbenv, dbtp, lsnp, op, info)
00524         DB_ENV *dbenv;
00525         DBT *dbtp;
00526         DB_LSN *lsnp;
00527         db_recops op;
00528         void *info;
00529 {
00530         __ham_copypage_args *argp;
00531         DB *file_dbp;
00532         DBC *dbc;
00533         DB_MPOOLFILE *mpf;
00534         PAGE *pagep;
00535         u_int32_t flags;
00536         int cmp_n, cmp_p, ret;
00537 
00538         pagep = NULL;
00539         COMPQUIET(info, NULL);
00540 
00541         REC_PRINT(__ham_copypage_print);
00542         REC_INTRO(__ham_copypage_read, 1, 0);
00543 
00544         flags = 0;
00545 
00546         /* This is the bucket page. */
00547         REC_FGET(mpf, argp->pgno, &pagep, donext);
00548 
00549         cmp_n = log_compare(lsnp, &LSN(pagep));
00550         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00551         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00552 
00553         if (cmp_p == 0 && DB_REDO(op)) {
00554                 /* Need to redo update described. */
00555                 memcpy(pagep, argp->page.data, argp->page.size);
00556                 PGNO(pagep) = argp->pgno;
00557                 PREV_PGNO(pagep) = PGNO_INVALID;
00558                 LSN(pagep) = *lsnp;
00559                 flags = DB_MPOOL_DIRTY;
00560         } else if (cmp_n == 0 && DB_UNDO(op)) {
00561                 /* Need to undo update described. */
00562                 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
00563                     argp->next_pgno, 0, P_HASH);
00564                 LSN(pagep) = argp->pagelsn;
00565                 flags = DB_MPOOL_DIRTY;
00566         }
00567         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00568                 goto out;
00569         pagep = NULL;
00570 
00571 donext: /* Now fix up the "next" page. */
00572         REC_FGET(mpf, argp->next_pgno, &pagep, do_nn);
00573 
00574         /* For REDO just update the LSN. For UNDO copy page back. */
00575         cmp_n = log_compare(lsnp, &LSN(pagep));
00576         cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
00577         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->nextlsn);
00578         flags = 0;
00579         if (cmp_p == 0 && DB_REDO(op)) {
00580                 LSN(pagep) = *lsnp;
00581                 flags = DB_MPOOL_DIRTY;
00582         } else if (cmp_n == 0 && DB_UNDO(op)) {
00583                 /* Need to undo update described. */
00584                 memcpy(pagep, argp->page.data, argp->page.size);
00585                 flags = DB_MPOOL_DIRTY;
00586         }
00587         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00588                 goto out;
00589         pagep = NULL;
00590 
00591         /* Now fix up the next's next page. */
00592 do_nn:  if (argp->nnext_pgno == PGNO_INVALID)
00593                 goto done;
00594 
00595         REC_FGET(mpf, argp->nnext_pgno, &pagep, done);
00596 
00597         cmp_n = log_compare(lsnp, &LSN(pagep));
00598         cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn);
00599         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->nnextlsn);
00600 
00601         flags = 0;
00602         if (cmp_p == 0 && DB_REDO(op)) {
00603                 /* Need to redo update described. */
00604                 PREV_PGNO(pagep) = argp->pgno;
00605                 LSN(pagep) = *lsnp;
00606                 flags = DB_MPOOL_DIRTY;
00607         } else if (cmp_n == 0 && DB_UNDO(op)) {
00608                 /* Need to undo update described. */
00609                 PREV_PGNO(pagep) = argp->next_pgno;
00610                 LSN(pagep) = argp->nnextlsn;
00611                 flags = DB_MPOOL_DIRTY;
00612         }
00613         if ((ret = __memp_fput(mpf, pagep, flags)) != 0)
00614                 goto out;
00615         pagep = NULL;
00616 
00617 done:   *lsnp = argp->prev_lsn;
00618         ret = 0;
00619 
00620 out:    if (pagep != NULL)
00621                 (void)__memp_fput(mpf, pagep, 0);
00622         REC_CLOSE;
00623 }
00624 
00625 /*
00626  * __ham_metagroup_recover --
00627  *      Recovery function for metagroup.
00628  *
00629  * PUBLIC: int __ham_metagroup_recover
00630  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00631  */
00632 int
00633 __ham_metagroup_recover(dbenv, dbtp, lsnp, op, info)
00634         DB_ENV *dbenv;
00635         DBT *dbtp;
00636         DB_LSN *lsnp;
00637         db_recops op;
00638         void *info;
00639 {
00640         __ham_metagroup_args *argp;
00641         HASH_CURSOR *hcp;
00642         DB *file_dbp;
00643         DBMETA *mmeta;
00644         DBC *dbc;
00645         DB_MPOOLFILE *mpf;
00646         PAGE *pagep;
00647         db_pgno_t pgno;
00648         u_int32_t flags, mmeta_flags;
00649         int cmp_n, cmp_p, did_alloc, did_recover, groupgrow, ret;
00650 
00651         COMPQUIET(info, NULL);
00652         mmeta_flags = 0;
00653         did_alloc = 0;
00654         mmeta = NULL;
00655         REC_PRINT(__ham_metagroup_print);
00656         REC_INTRO(__ham_metagroup_read, 1, 1);
00657 
00658         /*
00659          * This logs the virtual create of pages pgno to pgno + bucket
00660          * If HAVE_FTRUNCATE is not supported the mpool page-allocation is not
00661          * transaction protected, we can never undo it.  Even in an abort,
00662          * we have to allocate these pages to the hash table if they
00663          * were actually created.  In particular, during disaster
00664          * recovery the metapage may be before this point if we
00665          * are rolling backward.  If the file has not been extended
00666          * then the metapage could not have been updated.
00667          * The log record contains:
00668          * bucket: old maximum bucket
00669          * pgno: page number of the new bucket.
00670          * We round up on log calculations, so we can figure out if we are
00671          * about to double the hash table if argp->bucket+1 is a power of 2.
00672          * If it is, then we are allocating an entire doubling of pages,
00673          * otherwise, we are simply allocated one new page.
00674          */
00675         groupgrow =
00676             (u_int32_t)(1 << __db_log2(argp->bucket + 1)) == argp->bucket + 1;
00677         pgno = argp->pgno;
00678         if (argp->newalloc)
00679                 pgno += argp->bucket;
00680 
00681         flags = 0;
00682         pagep = NULL;
00683 #ifndef HAVE_FTRUNCATE
00684         flags = DB_MPOOL_CREATE;
00685 #endif
00686         ret = __memp_fget(mpf, &pgno, flags, &pagep);
00687 
00688 #ifdef HAVE_FTRUNCATE
00689         /* If we are undoing, then we don't want to create the page. */
00690         if (ret != 0 && DB_REDO(op))
00691                 ret = __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep);
00692         else if (ret == DB_PAGE_NOTFOUND)
00693                 goto do_meta;
00694 #endif
00695         if (ret != 0) {
00696                 if (ret != ENOSPC)
00697                         goto out;
00698                 pgno = 0;
00699                 goto do_meta;
00700         }
00701 
00702         /*
00703          * When we get here then either we did not grow the file
00704          * (groupgrow == 0) or we did grow the file and the allocation
00705          * of those new pages succeeded.
00706          */
00707         did_alloc = groupgrow;
00708 
00709         cmp_n = log_compare(lsnp, &LSN(pagep));
00710         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
00711         CHECK_LSN(dbenv, op, cmp_p, &LSN(pagep), &argp->pagelsn);
00712 
00713         flags = 0;
00714         if (cmp_p == 0 && DB_REDO(op)) {
00715                 pagep->lsn = *lsnp;
00716                 flags = DB_MPOOL_DIRTY;
00717         } else if (cmp_n == 0 && DB_UNDO(op)) {
00718 #ifdef HAVE_FTRUNCATE
00719                 /* If this record allocated the pages give them back. */
00720                 if (argp->newalloc) {
00721                         if (pagep != NULL && (ret =
00722                              __memp_fput(mpf, pagep, DB_MPOOL_DISCARD)) != 0)
00723                                 goto out;
00724                         pagep = NULL;
00725                         if ((ret = __memp_ftruncate(mpf, argp->pgno, 0)) != 0)
00726                                 goto out;
00727                 } else
00728 #endif
00729                 {
00730                         /*
00731                          * Otherwise just roll the page back to its
00732                          * previous state.
00733                          */
00734                         pagep->lsn = argp->pagelsn;
00735                         flags = DB_MPOOL_DIRTY;
00736                 }
00737         }
00738         if (pagep != NULL && (ret = __memp_fput(mpf, pagep, flags)) != 0)
00739                 goto out;
00740 
00741 do_meta:
00742         /* Now we have to update the meta-data page. */
00743         hcp = (HASH_CURSOR *)dbc->internal;
00744         if ((ret = __ham_get_meta(dbc)) != 0)
00745                 goto out;
00746         cmp_n = log_compare(lsnp, &hcp->hdr->dbmeta.lsn);
00747         cmp_p = log_compare(&hcp->hdr->dbmeta.lsn, &argp->metalsn);
00748         CHECK_LSN(dbenv, op, cmp_p, &hcp->hdr->dbmeta.lsn, &argp->metalsn);
00749         did_recover = 0;
00750         if (cmp_p == 0 && DB_REDO(op)) {
00751                 /* Redo the actual updating of bucket counts. */
00752                 ++hcp->hdr->max_bucket;
00753                 if (groupgrow) {
00754                         hcp->hdr->low_mask = hcp->hdr->high_mask;
00755                         hcp->hdr->high_mask =
00756                             (argp->bucket + 1) | hcp->hdr->low_mask;
00757                 }
00758                 hcp->hdr->dbmeta.lsn = *lsnp;
00759                 did_recover = 1;
00760         } else if (cmp_n == 0 && DB_UNDO(op)) {
00761                 /* Undo the actual updating of bucket counts. */
00762                 hcp->hdr->max_bucket = argp->bucket;
00763                 if (groupgrow) {
00764                         hcp->hdr->high_mask = argp->bucket;
00765                         hcp->hdr->low_mask = hcp->hdr->high_mask >> 1;
00766                 }
00767                 hcp->hdr->dbmeta.lsn = argp->metalsn;
00768                 did_recover = 1;
00769         }
00770 
00771         /*
00772          * Now we need to fix up the spares array.  Each entry in the
00773          * spares array indicates the beginning page number for the
00774          * indicated doubling.  We need to fill this in whenever the
00775          * spares array is invalid, if we never reclaim pages then
00776          * we have to allocate the pages to the spares array in both
00777          * the redo and undo cases.
00778          */
00779         if (did_alloc &&
00780 #ifdef HAVE_FTRUNCATE
00781             !DB_UNDO(op) &&
00782 #endif
00783             hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] == PGNO_INVALID) {
00784                 hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] =
00785                     (argp->pgno - argp->bucket) - 1;
00786                 did_recover = 1;
00787         }
00788 #ifdef HAVE_FTRUNCATE
00789         if (cmp_n == 0 && groupgrow && DB_UNDO(op)) {
00790                 hcp->hdr->spares[
00791                     __db_log2(argp->bucket + 1) + 1] = PGNO_INVALID;
00792                 did_recover = 1;
00793         }
00794 #endif
00795 
00796         /*
00797          * Finally, we need to potentially fix up the last_pgno field
00798          * in the master meta-data page (which may or may not be the
00799          * same as the hash header page).
00800          */
00801         if (argp->mmpgno != argp->mpgno) {
00802                 if ((ret = __memp_fget(mpf, &argp->mmpgno, 0, &mmeta)) != 0)
00803                         goto out;
00804                 mmeta_flags = 0;
00805                 cmp_n = log_compare(lsnp, &mmeta->lsn);
00806                 cmp_p = log_compare(&mmeta->lsn, &argp->mmetalsn);
00807                 if (cmp_p == 0 && DB_REDO(op))
00808                         mmeta->lsn = *lsnp;
00809                 else if (cmp_n == 0 && DB_UNDO(op))
00810                         mmeta->lsn = argp->mmetalsn;
00811         } else
00812                 mmeta = (DBMETA *)hcp->hdr;
00813 
00814 #ifdef HAVE_FTRUNCATE
00815         if (cmp_n == 0 && DB_UNDO(op))
00816                 mmeta->last_pgno = argp->last_pgno;
00817         else if (DB_REDO(op))
00818 #endif
00819         if (mmeta->last_pgno < pgno)
00820                 mmeta->last_pgno = pgno;
00821         mmeta_flags = DB_MPOOL_DIRTY;
00822 
00823         if (argp->mmpgno != argp->mpgno &&
00824             (ret = __memp_fput(mpf, mmeta, mmeta_flags)) != 0)
00825                 goto out;
00826         mmeta = NULL;
00827 
00828         if (did_recover)
00829                 F_SET(hcp, H_DIRTY);
00830 
00831 done:   *lsnp = argp->prev_lsn;
00832         ret = 0;
00833 
00834 out:    if (mmeta != NULL)
00835                 (void)__memp_fput(mpf, mmeta, 0);
00836         if (dbc != NULL)
00837                 (void)__ham_release_meta(dbc);
00838         if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
00839                 ret = 0;
00840 
00841         REC_CLOSE;
00842 }
00843 
00844 /*
00845  * __ham_groupalloc_recover --
00846  *      Recover the batch creation of a set of pages for a new database.
00847  *
00848  * PUBLIC: int __ham_groupalloc_recover
00849  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00850  */
00851 int
00852 __ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info)
00853         DB_ENV *dbenv;
00854         DBT *dbtp;
00855         DB_LSN *lsnp;
00856         db_recops op;
00857         void *info;
00858 {
00859         __ham_groupalloc_args *argp;
00860         DBMETA *mmeta;
00861         DB_MPOOLFILE *mpf;
00862         DB *file_dbp;
00863         DBC *dbc;
00864         PAGE *pagep;
00865         db_pgno_t pgno;
00866         int cmp_n, cmp_p, modified, ret;
00867 
00868         mmeta = NULL;
00869         modified = 0;
00870         REC_PRINT(__ham_groupalloc_print);
00871         REC_INTRO(__ham_groupalloc_read, 0, 0);
00872 
00873         pgno = PGNO_BASE_MD;
00874         if ((ret = __memp_fget(mpf, &pgno, 0, &mmeta)) != 0) {
00875                 if (DB_REDO(op)) {
00876                         ret = __db_pgerr(file_dbp, pgno, ret);
00877                         goto out;
00878                 } else
00879                         goto done;
00880         }
00881 
00882         cmp_n = log_compare(lsnp, &LSN(mmeta));
00883         cmp_p = log_compare(&LSN(mmeta), &argp->meta_lsn);
00884         CHECK_LSN(dbenv, op, cmp_p, &LSN(mmeta), &argp->meta_lsn);
00885 
00886         /*
00887          * Basically, we used mpool to allocate a chunk of pages.
00888          * We need to either add those to a free list (in the undo
00889          * case) or initialize them (in the redo case).
00890          *
00891          * If we are redoing and this is a hash subdatabase, it's possible
00892          * that the pages were never allocated, so we'd better check for
00893          * that and handle it here.
00894          */
00895         pgno = argp->start_pgno + argp->num - 1;
00896         if (DB_REDO(op)) {
00897                 if ((ret = __ham_alloc_pages(file_dbp, argp, lsnp)) != 0)
00898                         goto out;
00899                 if (cmp_p == 0) {
00900                         LSN(mmeta) = *lsnp;
00901                         modified = 1;
00902                 }
00903         } else if (DB_UNDO(op)) {
00904                 /*
00905                  * Fetch the last page and determine if it is in
00906                  * the post allocation state.
00907                  */
00908                 pagep = NULL;
00909                 if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) == 0) {
00910                         if (log_compare(&pagep->lsn, lsnp) != 0) {
00911                                 if ((ret = __memp_fput(mpf,
00912                                      pagep, DB_MPOOL_DISCARD)) != 0)
00913                                         goto out;
00914                                 pagep = NULL;
00915                         }
00916                 } else if (ret != DB_PAGE_NOTFOUND)
00917                         goto out;
00918 #ifdef HAVE_FTRUNCATE
00919                 COMPQUIET(info, NULL);
00920                 /*
00921                  * If the last page was allocated then truncate back
00922                  * to the first page.
00923                  */
00924                 if (pagep != NULL) {
00925                         if ((ret =
00926                             __memp_fput(mpf, pagep, DB_MPOOL_DISCARD)) != 0)
00927                                 goto out;
00928                         if ((ret =
00929                              __memp_ftruncate(mpf, argp->start_pgno, 0)) != 0)
00930                                 goto out;
00931                 }
00932 
00933                 /*
00934                  * If we are rolling back the metapage, then make
00935                  * sure it reflects the the correct last_pgno.
00936                  */
00937                 if (cmp_n == 0) {
00938                         mmeta->last_pgno = argp->last_pgno;
00939                         modified = 1;
00940                 }
00941                 pgno = 0;
00942 #else
00943                 /*
00944                  * Reset the last page back to its preallocation state.
00945                  */
00946                 if (pagep != NULL) {
00947                         if (log_compare(&pagep->lsn, lsnp) == 0)
00948                                 ZERO_LSN(pagep->lsn);
00949 
00950                         if ((ret =
00951                             __memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
00952                                 goto out;
00953                 }
00954                 /*
00955                  * Put the pages into the limbo list and free them later.
00956                  */
00957                 if ((ret = __db_add_limbo(dbenv,
00958                     info, argp->fileid, argp->start_pgno, argp->num)) != 0)
00959                         goto out;
00960 #endif
00961                 if (cmp_n == 0) {
00962                         LSN(mmeta) = argp->meta_lsn;
00963                         modified = 1;
00964                 }
00965         }
00966 
00967         /*
00968          * In both REDO and UNDO, we have grown the file and need to make
00969          * sure that last_pgno is correct.  If we HAVE_FTRUNCATE pgno
00970          * will only be valid on REDO.
00971          */
00972         if (pgno > mmeta->last_pgno) {
00973                 mmeta->last_pgno = pgno;
00974                 modified = 1;
00975         }
00976 
00977 done:   if (ret == 0)
00978                 *lsnp = argp->prev_lsn;
00979         ret = 0;
00980 
00981 out:    if (mmeta != NULL)
00982                 (void)__memp_fput(mpf, mmeta, modified ? DB_MPOOL_DIRTY : 0);
00983 
00984         if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
00985                 ret = 0;
00986         REC_CLOSE;
00987 }
00988 
00989 /*
00990  * __ham_alloc_pages --
00991  *
00992  * Called during redo of a file create.  We create new pages in the file
00993  * using the MPOOL_NEW_GROUP flag.  We then log the meta-data page with a
00994  * __crdel_metasub message.  If we manage to crash without the newly written
00995  * pages getting to disk (I'm not sure this can happen anywhere except our
00996  * test suite?!), then we need to go through a recreate the final pages.
00997  * Hash normally has holes in its files and handles them appropriately.
00998  */
00999 static int
01000 __ham_alloc_pages(dbp, argp, lsnp)
01001         DB *dbp;
01002         __ham_groupalloc_args *argp;
01003         DB_LSN *lsnp;
01004 {
01005         DB_MPOOLFILE *mpf;
01006         PAGE *pagep;
01007         db_pgno_t pgno;
01008         int ret;
01009 
01010         mpf = dbp->mpf;
01011 
01012         /* Read the last page of the allocation. */
01013         pgno = argp->start_pgno + argp->num - 1;
01014 
01015         /* If the page exists, and it has been initialized, then we're done. */
01016         if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) == 0) {
01017                 if (NUM_ENT(pagep) == 0 && IS_ZERO_LSN(pagep->lsn))
01018                         goto reinit_page;
01019                 if ((ret = __memp_fput(mpf, pagep, 0)) != 0)
01020                         return (ret);
01021                 return (0);
01022         }
01023 
01024         /* Had to create the page. */
01025         if ((ret = __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0)
01026                 return (__db_pgerr(dbp, pgno, ret));
01027 
01028 reinit_page:
01029         /* Initialize the newly allocated page. */
01030         P_INIT(pagep, dbp->pgsize, pgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
01031         pagep->lsn = *lsnp;
01032 
01033         if ((ret = __memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
01034                 return (ret);
01035 
01036         return (0);
01037 }
01038 
01039 /*
01040  * __ham_curadj_recover --
01041  *      Undo cursor adjustments if a subtransaction fails.
01042  *
01043  * PUBLIC: int __ham_curadj_recover
01044  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01045  */
01046 int
01047 __ham_curadj_recover(dbenv, dbtp, lsnp, op, info)
01048         DB_ENV *dbenv;
01049         DBT *dbtp;
01050         DB_LSN *lsnp;
01051         db_recops op;
01052         void *info;
01053 {
01054         __ham_curadj_args *argp;
01055         DB_MPOOLFILE *mpf;
01056         DB *file_dbp;
01057         DBC *dbc;
01058         int ret;
01059         HASH_CURSOR *hcp;
01060 
01061         COMPQUIET(info, NULL);
01062         REC_PRINT(__ham_curadj_print);
01063         REC_INTRO(__ham_curadj_read, 0, 1);
01064 
01065         if (op != DB_TXN_ABORT)
01066                 goto done;
01067 
01068         /*
01069          * Undo the adjustment by reinitializing the the cursor to look like
01070          * the one that was used to do the adjustment, then we invert the
01071          * add so that undo the adjustment.
01072          */
01073         hcp = (HASH_CURSOR *)dbc->internal;
01074         hcp->pgno = argp->pgno;
01075         hcp->indx = argp->indx;
01076         hcp->dup_off = argp->dup_off;
01077         hcp->order = argp->order;
01078         if (!argp->add)
01079                 F_SET(hcp, H_DELETED);
01080         (void)__ham_c_update(dbc, argp->len, !argp->add, argp->is_dup);
01081 
01082 done:   *lsnp = argp->prev_lsn;
01083 out:    REC_CLOSE;
01084 }
01085 
01086 /*
01087  * __ham_chgpg_recover --
01088  *      Undo cursor adjustments if a subtransaction fails.
01089  *
01090  * PUBLIC: int __ham_chgpg_recover
01091  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
01092  */
01093 int
01094 __ham_chgpg_recover(dbenv, dbtp, lsnp, op, info)
01095         DB_ENV *dbenv;
01096         DBT *dbtp;
01097         DB_LSN *lsnp;
01098         db_recops op;
01099         void *info;
01100 {
01101         __ham_chgpg_args *argp;
01102         BTREE_CURSOR *opdcp;
01103         DB_MPOOLFILE *mpf;
01104         DB *file_dbp, *ldbp;
01105         DBC *dbc;
01106         int ret;
01107         DBC *cp;
01108         HASH_CURSOR *lcp;
01109         u_int32_t order, indx;
01110 
01111         COMPQUIET(info, NULL);
01112         REC_PRINT(__ham_chgpg_print);
01113         REC_INTRO(__ham_chgpg_read, 0, 0);
01114 
01115         if (op != DB_TXN_ABORT)
01116                 goto done;
01117 
01118         /* Overloaded fields for DB_HAM_DEL*PG */
01119         indx = argp->old_indx;
01120         order = argp->new_indx;
01121 
01122         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
01123         for (ldbp = __dblist_get(dbenv, file_dbp->adj_fileid);
01124             ldbp != NULL && ldbp->adj_fileid == file_dbp->adj_fileid;
01125             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
01126                 MUTEX_LOCK(dbenv, file_dbp->mutex);
01127 
01128                 for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
01129                     cp = TAILQ_NEXT(cp, links)) {
01130                         lcp = (HASH_CURSOR *)cp->internal;
01131 
01132                         switch (argp->mode) {
01133                         case DB_HAM_DELFIRSTPG:
01134                                 if (lcp->pgno != argp->new_pgno)
01135                                         break;
01136                                 if (lcp->indx != indx ||
01137                                     !F_ISSET(lcp, H_DELETED) ||
01138                                     lcp->order >= order) {
01139                                         lcp->pgno = argp->old_pgno;
01140                                         if (lcp->indx == indx)
01141                                                 lcp->order -= order;
01142                                 }
01143                                 break;
01144                         case DB_HAM_DELMIDPG:
01145                         case DB_HAM_DELLASTPG:
01146                                 if (lcp->pgno == argp->new_pgno &&
01147                                     lcp->indx == indx &&
01148                                     F_ISSET(lcp, H_DELETED) &&
01149                                     lcp->order >= order) {
01150                                         lcp->pgno = argp->old_pgno;
01151                                         lcp->order -= order;
01152                                         lcp->indx = 0;
01153                                 }
01154                                 break;
01155                         case DB_HAM_CHGPG:
01156                                 /*
01157                                  * If we're doing a CHGPG, we're undoing
01158                                  * the move of a non-deleted item to a
01159                                  * new page.  Any cursors with the deleted
01160                                  * flag set do not belong to this item;
01161                                  * don't touch them.
01162                                  */
01163                                 if (F_ISSET(lcp, H_DELETED))
01164                                         break;
01165                                 /* FALLTHROUGH */
01166                         case DB_HAM_SPLIT:
01167                                 if (lcp->pgno == argp->new_pgno &&
01168                                     lcp->indx == argp->new_indx) {
01169                                         lcp->indx = argp->old_indx;
01170                                         lcp->pgno = argp->old_pgno;
01171                                 }
01172                                 break;
01173                         case DB_HAM_DUP:
01174                                 if (lcp->opd == NULL)
01175                                         break;
01176                                 opdcp = (BTREE_CURSOR *)lcp->opd->internal;
01177                                 if (opdcp->pgno != argp->new_pgno ||
01178                                     opdcp->indx != argp->new_indx)
01179                                         break;
01180 
01181                                 if (F_ISSET(opdcp, C_DELETED))
01182                                         F_SET(lcp, H_DELETED);
01183                                 /*
01184                                  * We can't close a cursor while we have the
01185                                  * dbp mutex locked, since c_close reacquires
01186                                  * it.  It should be safe to drop the mutex
01187                                  * here, though, since newly opened cursors
01188                                  * are put only at the end of the tailq and
01189                                  * the cursor we're adjusting can't be closed
01190                                  * under us.
01191                                  */
01192                                 MUTEX_UNLOCK(dbenv, file_dbp->mutex);
01193                                 if ((ret = __db_c_close(lcp->opd)) != 0)
01194                                         goto out;
01195                                 MUTEX_LOCK(dbenv, file_dbp->mutex);
01196                                 lcp->opd = NULL;
01197                                 break;
01198                         }
01199                 }
01200                 MUTEX_UNLOCK(dbenv, file_dbp->mutex);
01201         }
01202         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
01203 
01204 done:   *lsnp = argp->prev_lsn;
01205 out:    REC_CLOSE;
01206 }

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