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

bt_curadj.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: bt_curadj.c,v 12.3 2005/07/20 16:50:45 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #endif
00015 
00016 #include "db_int.h"
00017 #include "dbinc/db_page.h"
00018 #include "dbinc/btree.h"
00019 
00020 static int __bam_opd_cursor __P((DB *, DBC *, db_pgno_t, u_int32_t, u_int32_t));
00021 
00022 /*
00023  * Cursor adjustments are logged if they are for subtransactions.  This is
00024  * because it's possible for a subtransaction to adjust cursors which will
00025  * still be active after the subtransaction aborts, and so which must be
00026  * restored to their previous locations.  Cursors that can be both affected
00027  * by our cursor adjustments and active after our transaction aborts can
00028  * only be found in our parent transaction -- cursors in other transactions,
00029  * including other child transactions of our parent, must have conflicting
00030  * locker IDs, and so cannot be affected by adjustments in this transaction.
00031  */
00032 
00033 /*
00034  * __bam_ca_delete --
00035  *      Update the cursors when items are deleted and when already deleted
00036  *      items are overwritten.  Return the number of relevant cursors found.
00037  *
00038  * PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int, int *));
00039  */
00040 int
00041 __bam_ca_delete(dbp, pgno, indx, delete, countp)
00042         DB *dbp;
00043         db_pgno_t pgno;
00044         u_int32_t indx;
00045         int delete, *countp;
00046 {
00047         BTREE_CURSOR *cp;
00048         DB *ldbp;
00049         DB_ENV *dbenv;
00050         DBC *dbc;
00051         int count;              /* !!!: Has to contain max number of cursors. */
00052 
00053         dbenv = dbp->dbenv;
00054 
00055         /*
00056          * Adjust the cursors.  We have the page write locked, so the
00057          * only other cursors that can be pointing at a page are
00058          * those in the same thread of control.  Unfortunately, we don't
00059          * know that they're using the same DB handle, so traverse
00060          * all matching DB handles in the same DB_ENV, then all cursors
00061          * on each matching DB handle.
00062          *
00063          * Each cursor is single-threaded, so we only need to lock the
00064          * list of DBs and then the list of cursors in each DB.
00065          */
00066         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00067         for (count = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00068             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00069             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00070                 MUTEX_LOCK(dbenv, dbp->mutex);
00071                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00072                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00073                         cp = (BTREE_CURSOR *)dbc->internal;
00074                         if (cp->pgno == pgno && cp->indx == indx) {
00075                                 /*
00076                                  * [#8032] This assert is checking
00077                                  * for possible race conditions where we
00078                                  * hold a cursor position without a lock.
00079                                  * Unfortunately, there are paths in the
00080                                  * Btree code that do not satisfy these
00081                                  * conditions. None of them are known to
00082                                  * be a problem, but this assert should
00083                                  * be re-activated when the Btree stack
00084                                  * code is re-written.
00085                                 DB_ASSERT(!STD_LOCKING(dbc) ||
00086                                     cp->lock_mode != DB_LOCK_NG);
00087                                  */
00088                                 if (delete)
00089                                         F_SET(cp, C_DELETED);
00090                                 else
00091                                         F_CLR(cp, C_DELETED);
00092                                 ++count;
00093                         }
00094                 }
00095                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00096         }
00097         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00098 
00099         if (countp != NULL)
00100                 *countp = count;
00101         return (0);
00102 }
00103 
00104 /*
00105  * __ram_ca_delete --
00106  *      Return if any relevant cursors found.
00107  *
00108  * PUBLIC: int __ram_ca_delete __P((DB *, db_pgno_t, int *));
00109  */
00110 int
00111 __ram_ca_delete(dbp, root_pgno, foundp)
00112         DB *dbp;
00113         db_pgno_t root_pgno;
00114         int *foundp;
00115 {
00116         DB *ldbp;
00117         DBC *dbc;
00118         DB_ENV *dbenv;
00119         int found;
00120 
00121         found = 0;
00122         dbenv = dbp->dbenv;
00123 
00124         /*
00125          * Review the cursors.  See the comment in __bam_ca_delete().
00126          */
00127         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00128         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00129             found == 0 && ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00130             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00131                 MUTEX_LOCK(dbenv, dbp->mutex);
00132                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00133                     found == 0 && dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
00134                         if (dbc->internal->root == root_pgno)
00135                                 found = 1;
00136                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00137         }
00138         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00139 
00140         *foundp = found;
00141         return (0);
00142 }
00143 
00144 /*
00145  * __bam_ca_di --
00146  *      Adjust the cursors during a delete or insert.
00147  *
00148  * PUBLIC: int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int));
00149  */
00150 int
00151 __bam_ca_di(my_dbc, pgno, indx, adjust)
00152         DBC *my_dbc;
00153         db_pgno_t pgno;
00154         u_int32_t indx;
00155         int adjust;
00156 {
00157         DB *dbp, *ldbp;
00158         DB_ENV *dbenv;
00159         DB_LSN lsn;
00160         DB_TXN *my_txn;
00161         DBC *dbc;
00162         DBC_INTERNAL *cp;
00163         int found, ret;
00164 
00165         dbp = my_dbc->dbp;
00166         dbenv = dbp->dbenv;
00167 
00168         my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
00169 
00170         /*
00171          * Adjust the cursors.  See the comment in __bam_ca_delete().
00172          */
00173         found = 0;
00174         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00175         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00176             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00177             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00178                 MUTEX_LOCK(dbenv, dbp->mutex);
00179                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00180                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00181                         if (dbc->dbtype == DB_RECNO)
00182                                 continue;
00183                         cp = dbc->internal;
00184                         if (cp->pgno == pgno && cp->indx >= indx) {
00185                                 /* Cursor indices should never be negative. */
00186                                 DB_ASSERT(cp->indx != 0 || adjust > 0);
00187                                 /* [#8032]
00188                                 DB_ASSERT(!STD_LOCKING(dbc) ||
00189                                     cp->lock_mode != DB_LOCK_NG);
00190                                 */
00191                                 cp->indx += adjust;
00192                                 if (my_txn != NULL && dbc->txn != my_txn)
00193                                         found = 1;
00194                         }
00195                 }
00196                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00197         }
00198         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00199 
00200         if (found != 0 && DBC_LOGGING(my_dbc)) {
00201                 if ((ret = __bam_curadj_log(dbp, my_dbc->txn, &lsn, 0,
00202                     DB_CA_DI, pgno, 0, 0, (u_int32_t)adjust, indx, 0)) != 0)
00203                         return (ret);
00204         }
00205 
00206         return (0);
00207 }
00208 
00209 /*
00210  * __bam_opd_cursor -- create a new opd cursor.
00211  */
00212 static int
00213 __bam_opd_cursor(dbp, dbc, first, tpgno, ti)
00214         DB *dbp;
00215         DBC *dbc;
00216         db_pgno_t tpgno;
00217         u_int32_t first, ti;
00218 {
00219         BTREE_CURSOR *cp, *orig_cp;
00220         DBC *dbc_nopd;
00221         int ret;
00222 
00223         orig_cp = (BTREE_CURSOR *)dbc->internal;
00224         dbc_nopd = NULL;
00225 
00226         /*
00227          * Allocate a new cursor and create the stack.  If duplicates
00228          * are sorted, we've just created an off-page duplicate Btree.
00229          * If duplicates aren't sorted, we've just created a Recno tree.
00230          *
00231          * Note that in order to get here at all, there shouldn't be
00232          * an old off-page dup cursor--to augment the checking db_c_newopd
00233          * will do, assert this.
00234          */
00235         DB_ASSERT(orig_cp->opd == NULL);
00236         if ((ret = __db_c_newopd(dbc, tpgno, orig_cp->opd, &dbc_nopd)) != 0)
00237                 return (ret);
00238 
00239         cp = (BTREE_CURSOR *)dbc_nopd->internal;
00240         cp->pgno = tpgno;
00241         cp->indx = ti;
00242 
00243         if (dbp->dup_compare == NULL) {
00244                 /*
00245                  * Converting to off-page Recno trees is tricky.  The
00246                  * record number for the cursor is the index + 1 (to
00247                  * convert to 1-based record numbers).
00248                  */
00249                 cp->recno = ti + 1;
00250         }
00251 
00252         /*
00253          * Transfer the deleted flag from the top-level cursor to the
00254          * created one.
00255          */
00256         if (F_ISSET(orig_cp, C_DELETED)) {
00257                 F_SET(cp, C_DELETED);
00258                 F_CLR(orig_cp, C_DELETED);
00259         }
00260 
00261         /* Stack the cursors and reset the initial cursor's index. */
00262         orig_cp->opd = dbc_nopd;
00263         orig_cp->indx = first;
00264         return (0);
00265 }
00266 
00267 /*
00268  * __bam_ca_dup --
00269  *      Adjust the cursors when moving items from a leaf page to a duplicates
00270  *      page.
00271  *
00272  * PUBLIC: int __bam_ca_dup __P((DBC *,
00273  * PUBLIC:    u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
00274  */
00275 int
00276 __bam_ca_dup(my_dbc, first, fpgno, fi, tpgno, ti)
00277         DBC *my_dbc;
00278         db_pgno_t fpgno, tpgno;
00279         u_int32_t first, fi, ti;
00280 {
00281         BTREE_CURSOR *orig_cp;
00282         DB *dbp, *ldbp;
00283         DBC *dbc;
00284         DB_ENV *dbenv;
00285         DB_LSN lsn;
00286         DB_TXN *my_txn;
00287         int found, ret;
00288 
00289         dbp = my_dbc->dbp;
00290         dbenv = dbp->dbenv;
00291         my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
00292 
00293         /*
00294          * Adjust the cursors.  See the comment in __bam_ca_delete().
00295          */
00296         found = 0;
00297         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00298         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00299             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00300             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00301 loop:           MUTEX_LOCK(dbenv, dbp->mutex);
00302                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00303                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00304                         /* Find cursors pointing to this record. */
00305                         orig_cp = (BTREE_CURSOR *)dbc->internal;
00306                         if (orig_cp->pgno != fpgno || orig_cp->indx != fi)
00307                                 continue;
00308 
00309                         /*
00310                          * Since we rescan the list see if this is already
00311                          * converted.
00312                          */
00313                         if (orig_cp->opd != NULL)
00314                                 continue;
00315 
00316                         MUTEX_UNLOCK(dbenv, dbp->mutex);
00317                         /* [#8032]
00318                         DB_ASSERT(!STD_LOCKING(dbc) ||
00319                             orig_cp->lock_mode != DB_LOCK_NG);
00320                         */
00321                         if ((ret = __bam_opd_cursor(dbp,
00322                             dbc, first, tpgno, ti)) !=0)
00323                                 return (ret);
00324                         if (my_txn != NULL && dbc->txn != my_txn)
00325                                 found = 1;
00326                         /* We released the mutex to get a cursor, start over. */
00327                         goto loop;
00328                 }
00329                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00330         }
00331         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00332 
00333         if (found != 0 && DBC_LOGGING(my_dbc)) {
00334                 if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
00335                     &lsn, 0, DB_CA_DUP, fpgno, tpgno, 0, first, fi, ti)) != 0)
00336                         return (ret);
00337         }
00338         return (0);
00339 }
00340 
00341 /*
00342  * __bam_ca_undodup --
00343  *      Adjust the cursors when returning items to a leaf page
00344  *      from a duplicate page.
00345  *      Called only during undo processing.
00346  *
00347  * PUBLIC: int __bam_ca_undodup __P((DB *,
00348  * PUBLIC:    u_int32_t, db_pgno_t, u_int32_t, u_int32_t));
00349  */
00350 int
00351 __bam_ca_undodup(dbp, first, fpgno, fi, ti)
00352         DB *dbp;
00353         db_pgno_t fpgno;
00354         u_int32_t first, fi, ti;
00355 {
00356         BTREE_CURSOR *orig_cp;
00357         DB *ldbp;
00358         DBC *dbc;
00359         DB_ENV *dbenv;
00360         int ret;
00361 
00362         dbenv = dbp->dbenv;
00363 
00364         /*
00365          * Adjust the cursors.  See the comment in __bam_ca_delete().
00366          */
00367         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00368         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00369             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00370             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00371 loop:           MUTEX_LOCK(dbenv, dbp->mutex);
00372                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00373                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00374                         orig_cp = (BTREE_CURSOR *)dbc->internal;
00375 
00376                         /*
00377                          * A note on the orig_cp->opd != NULL requirement here:
00378                          * it's possible that there's a cursor that refers to
00379                          * the same duplicate set, but which has no opd cursor,
00380                          * because it refers to a different item and we took
00381                          * care of it while processing a previous record.
00382                          */
00383                         if (orig_cp->pgno != fpgno ||
00384                             orig_cp->indx != first ||
00385                             orig_cp->opd == NULL || ((BTREE_CURSOR *)
00386                             orig_cp->opd->internal)->indx != ti)
00387                                 continue;
00388                         MUTEX_UNLOCK(dbenv, dbp->mutex);
00389                         if ((ret = __db_c_close(orig_cp->opd)) != 0)
00390                                 return (ret);
00391                         orig_cp->opd = NULL;
00392                         orig_cp->indx = fi;
00393                         /*
00394                          * We released the mutex to free a cursor,
00395                          * start over.
00396                          */
00397                         goto loop;
00398                 }
00399                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00400         }
00401         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00402 
00403         return (0);
00404 }
00405 
00406 /*
00407  * __bam_ca_rsplit --
00408  *      Adjust the cursors when doing reverse splits.
00409  *
00410  * PUBLIC: int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t));
00411  */
00412 int
00413 __bam_ca_rsplit(my_dbc, fpgno, tpgno)
00414         DBC* my_dbc;
00415         db_pgno_t fpgno, tpgno;
00416 {
00417         DB *dbp, *ldbp;
00418         DBC *dbc;
00419         DB_ENV *dbenv;
00420         DB_LSN lsn;
00421         DB_TXN *my_txn;
00422         int found, ret;
00423 
00424         dbp = my_dbc->dbp;
00425         dbenv = dbp->dbenv;
00426         my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
00427 
00428         /*
00429          * Adjust the cursors.  See the comment in __bam_ca_delete().
00430          */
00431         found = 0;
00432         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00433         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00434             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00435             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00436                 MUTEX_LOCK(dbenv, dbp->mutex);
00437                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00438                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00439                         if (dbc->dbtype == DB_RECNO)
00440                                 continue;
00441                         if (dbc->internal->pgno == fpgno) {
00442                                 dbc->internal->pgno = tpgno;
00443                                 /* [#8032]
00444                                 DB_ASSERT(!STD_LOCKING(dbc) ||
00445                                     dbc->internal->lock_mode != DB_LOCK_NG);
00446                                 */
00447                                 if (my_txn != NULL && dbc->txn != my_txn)
00448                                         found = 1;
00449                         }
00450                 }
00451                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00452         }
00453         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00454 
00455         if (found != 0 && DBC_LOGGING(my_dbc)) {
00456                 if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
00457                     &lsn, 0, DB_CA_RSPLIT, fpgno, tpgno, 0, 0, 0, 0)) != 0)
00458                         return (ret);
00459         }
00460         return (0);
00461 }
00462 
00463 /*
00464  * __bam_ca_split --
00465  *      Adjust the cursors when splitting a page.
00466  *
00467  * PUBLIC: int __bam_ca_split __P((DBC *,
00468  * PUBLIC:    db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
00469  */
00470 int
00471 __bam_ca_split(my_dbc, ppgno, lpgno, rpgno, split_indx, cleft)
00472         DBC *my_dbc;
00473         db_pgno_t ppgno, lpgno, rpgno;
00474         u_int32_t split_indx;
00475         int cleft;
00476 {
00477         DB *dbp, *ldbp;
00478         DBC *dbc;
00479         DBC_INTERNAL *cp;
00480         DB_ENV *dbenv;
00481         DB_LSN lsn;
00482         DB_TXN *my_txn;
00483         int found, ret;
00484 
00485         dbp = my_dbc->dbp;
00486         dbenv = dbp->dbenv;
00487         my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
00488 
00489         /*
00490          * Adjust the cursors.  See the comment in __bam_ca_delete().
00491          *
00492          * If splitting the page that a cursor was on, the cursor has to be
00493          * adjusted to point to the same record as before the split.  Most
00494          * of the time we don't adjust pointers to the left page, because
00495          * we're going to copy its contents back over the original page.  If
00496          * the cursor is on the right page, it is decremented by the number of
00497          * records split to the left page.
00498          */
00499         found = 0;
00500         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00501         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00502             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00503             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00504                 MUTEX_LOCK(dbenv, dbp->mutex);
00505                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00506                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00507                         if (dbc->dbtype == DB_RECNO)
00508                                 continue;
00509                         cp = dbc->internal;
00510                         if (cp->pgno == ppgno) {
00511                                 /* [#8032]
00512                                 DB_ASSERT(!STD_LOCKING(dbc) ||
00513                                     cp->lock_mode != DB_LOCK_NG);
00514                                 */
00515                                 if (my_txn != NULL && dbc->txn != my_txn)
00516                                         found = 1;
00517                                 if (cp->indx < split_indx) {
00518                                         if (cleft)
00519                                                 cp->pgno = lpgno;
00520                                 } else {
00521                                         cp->pgno = rpgno;
00522                                         cp->indx -= split_indx;
00523                                 }
00524                         }
00525                 }
00526                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00527         }
00528         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00529 
00530         if (found != 0 && DBC_LOGGING(my_dbc)) {
00531                 if ((ret = __bam_curadj_log(dbp,
00532                     my_dbc->txn, &lsn, 0, DB_CA_SPLIT, ppgno, rpgno,
00533                     cleft ? lpgno : PGNO_INVALID, 0, split_indx, 0)) != 0)
00534                         return (ret);
00535         }
00536 
00537         return (0);
00538 }
00539 
00540 /*
00541  * __bam_ca_undosplit --
00542  *      Adjust the cursors when undoing a split of a page.
00543  *      If we grew a level we will execute this for both the
00544  *      left and the right pages.
00545  *      Called only during undo processing.
00546  *
00547  * PUBLIC: int __bam_ca_undosplit __P((DB *,
00548  * PUBLIC:    db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t));
00549  */
00550 int
00551 __bam_ca_undosplit(dbp, frompgno, topgno, lpgno, split_indx)
00552         DB *dbp;
00553         db_pgno_t frompgno, topgno, lpgno;
00554         u_int32_t split_indx;
00555 {
00556         DB *ldbp;
00557         DBC *dbc;
00558         DB_ENV *dbenv;
00559         DBC_INTERNAL *cp;
00560 
00561         dbenv = dbp->dbenv;
00562 
00563         /*
00564          * Adjust the cursors.  See the comment in __bam_ca_delete().
00565          *
00566          * When backing out a split, we move the cursor back
00567          * to the original offset and bump it by the split_indx.
00568          */
00569         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00570         for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00571             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00572             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00573                 MUTEX_LOCK(dbenv, dbp->mutex);
00574                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00575                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00576                         if (dbc->dbtype == DB_RECNO)
00577                                 continue;
00578                         cp = dbc->internal;
00579                         if (cp->pgno == topgno) {
00580                                 cp->pgno = frompgno;
00581                                 cp->indx += split_indx;
00582                         } else if (cp->pgno == lpgno)
00583                                 cp->pgno = frompgno;
00584                 }
00585                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00586         }
00587         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00588 
00589         return (0);
00590 }

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