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

dbreg_util.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1997-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: dbreg_util.c,v 12.10 2005/10/12 15:01:47 margo Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <string.h>
00015 #endif
00016 
00017 #include "db_int.h"
00018 #include "dbinc/db_page.h"
00019 #include "dbinc/db_am.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/fop.h"
00022 #include "dbinc/log.h"
00023 #include "dbinc/mp.h"
00024 #include "dbinc/txn.h"
00025 
00026 static int __dbreg_check_master __P((DB_ENV *, u_int8_t *, char *));
00027 
00028 /*
00029  * __dbreg_add_dbentry --
00030  *      Adds a DB entry to the dbreg DB entry table.
00031  *
00032  * PUBLIC: int __dbreg_add_dbentry __P((DB_ENV *, DB_LOG *, DB *, int32_t));
00033  */
00034 int
00035 __dbreg_add_dbentry(dbenv, dblp, dbp, ndx)
00036         DB_ENV *dbenv;
00037         DB_LOG *dblp;
00038         DB *dbp;
00039         int32_t ndx;
00040 {
00041         int32_t i;
00042         int ret;
00043 
00044         ret = 0;
00045 
00046         MUTEX_LOCK(dbenv, dblp->mtx_dbreg);
00047 
00048         /*
00049          * Check if we need to grow the table.  Note, ndx is 0-based (the
00050          * index into the DB entry table) an dbentry_cnt is 1-based, the
00051          * number of available slots.
00052          */
00053         if (dblp->dbentry_cnt <= ndx) {
00054                 if ((ret = __os_realloc(dbenv,
00055                     (size_t)(ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY),
00056                     &dblp->dbentry)) != 0)
00057                         goto err;
00058 
00059                 /* Initialize the new entries. */
00060                 for (i = dblp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
00061                         dblp->dbentry[i].dbp = NULL;
00062                         dblp->dbentry[i].deleted = 0;
00063                 }
00064                 dblp->dbentry_cnt = i;
00065         }
00066 
00067         DB_ASSERT(dblp->dbentry[ndx].dbp == NULL);
00068         dblp->dbentry[ndx].deleted = dbp == NULL;
00069         dblp->dbentry[ndx].dbp = dbp;
00070 
00071 err:    MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg);
00072         return (ret);
00073 }
00074 
00075 /*
00076  * __dbreg_rem_dbentry
00077  *      Remove an entry from the DB entry table.
00078  *
00079  * PUBLIC: int __dbreg_rem_dbentry __P((DB_LOG *, int32_t));
00080  */
00081 int
00082 __dbreg_rem_dbentry(dblp, ndx)
00083         DB_LOG *dblp;
00084         int32_t ndx;
00085 {
00086         MUTEX_LOCK(dblp->dbenv, dblp->mtx_dbreg);
00087         if (dblp->dbentry_cnt > ndx) {
00088                 dblp->dbentry[ndx].dbp = NULL;
00089                 dblp->dbentry[ndx].deleted = 0;
00090         }
00091         MUTEX_UNLOCK(dblp->dbenv, dblp->mtx_dbreg);
00092 
00093         return (0);
00094 }
00095 
00096 /*
00097  * __dbreg_log_files --
00098  *      Put a DBREG_CHKPNT/CLOSE log record for each open database.
00099  *
00100  * PUBLIC: int __dbreg_log_files __P((DB_ENV *));
00101  */
00102 int
00103 __dbreg_log_files(dbenv)
00104         DB_ENV *dbenv;
00105 {
00106         DB_LOG *dblp;
00107         DB_LSN r_unused;
00108         DBT *dbtp, fid_dbt, t;
00109         FNAME *fnp;
00110         LOG *lp;
00111         int ret;
00112 
00113         dblp = dbenv->lg_handle;
00114         lp = dblp->reginfo.primary;
00115 
00116         ret = 0;
00117 
00118         MUTEX_LOCK(dbenv, lp->mtx_filelist);
00119 
00120         for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00121             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
00122 
00123                 if (fnp->name_off == INVALID_ROFF)
00124                         dbtp = NULL;
00125                 else {
00126                         memset(&t, 0, sizeof(t));
00127                         t.data = R_ADDR(&dblp->reginfo, fnp->name_off);
00128                         t.size = (u_int32_t)strlen(t.data) + 1;
00129                         dbtp = &t;
00130                 }
00131                 memset(&fid_dbt, 0, sizeof(fid_dbt));
00132                 fid_dbt.data = fnp->ufid;
00133                 fid_dbt.size = DB_FILE_ID_LEN;
00134                 /*
00135                  * Output DBREG_CHKPNT records which will be processed during
00136                  * the OPENFILES pass of recovery.  At the end of recovery we
00137                  * want to output the files that were open so a future recovery
00138                  * run will have the correct files open during a backward pass.
00139                  * For this we output DBREG_RCLOSE records so the files will be
00140                  * closed on the forward pass.
00141                  */
00142                 if ((ret = __dbreg_register_log(dbenv,
00143                     NULL, &r_unused,
00144                     F_ISSET(fnp, DB_FNAME_DURABLE) ? 0 : DB_LOG_NOT_DURABLE,
00145                     F_ISSET(dblp, DBLOG_RECOVER) ? DBREG_RCLOSE : DBREG_CHKPNT,
00146                     dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno,
00147                     TXN_INVALID)) != 0)
00148                         break;
00149         }
00150 
00151         MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00152 
00153         return (ret);
00154 }
00155 
00156 /*
00157  * __dbreg_close_files --
00158  *      Remove the id's of open files and actually close those
00159  *      files that were opened by the recovery daemon.  We sync the
00160  *      file, unless its mpf pointer has been NULLed by a db_remove or
00161  *      db_rename.  We may not have flushed the log_register record that
00162  *      closes the file.
00163  *
00164  * PUBLIC: int __dbreg_close_files __P((DB_ENV *));
00165  */
00166 int
00167 __dbreg_close_files(dbenv)
00168         DB_ENV *dbenv;
00169 {
00170         DB_LOG *dblp;
00171         DB *dbp;
00172         int ret, t_ret;
00173         int32_t i;
00174 
00175         /* If we haven't initialized logging, we have nothing to do. */
00176         if (!LOGGING_ON(dbenv))
00177                 return (0);
00178 
00179         dblp = dbenv->lg_handle;
00180         ret = 0;
00181         MUTEX_LOCK(dbenv, dblp->mtx_dbreg);
00182         for (i = 0; i < dblp->dbentry_cnt; i++) {
00183                 /*
00184                  * We only want to close dbps that recovery opened.  Any
00185                  * dbps that weren't opened by recovery but show up here
00186                  * are about to be unconditionally removed from the table.
00187                  * Before doing so, we need to revoke their log fileids
00188                  * so that we don't end up leaving around FNAME entries
00189                  * for dbps that shouldn't have them.
00190                  *
00191                  * Any FNAME entries that were marked NOTLOGGED had the
00192                  * log write fail while they were being closed.  Since it's
00193                  * too late to be logging now we flag that as a failure
00194                  * so recovery will be run.  This will get returned by
00195                  * __dbreg_revoke_id.
00196                  */
00197                 if ((dbp = dblp->dbentry[i].dbp) != NULL) {
00198                         /*
00199                          * It's unsafe to call DB->close or revoke_id
00200                          * while holding the thread lock, because
00201                          * we'll call __dbreg_rem_dbentry and grab it again.
00202                          *
00203                          * Just drop it.  Since dbreg ids go monotonically
00204                          * upward, concurrent opens should be safe, and the
00205                          * user should have no business closing files while
00206                          * we're in this loop anyway--we're in the process of
00207                          * making all outstanding dbps invalid.
00208                          */
00209                         MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg);
00210                         if (F_ISSET(dbp, DB_AM_RECOVER))
00211                                 t_ret = __db_close(dbp,
00212                                      NULL, dbp->mpf == NULL ? DB_NOSYNC : 0);
00213                         else
00214                                 t_ret = __dbreg_revoke_id(
00215                                      dbp, 0, DB_LOGFILEID_INVALID);
00216                         if (ret == 0)
00217                                 ret = t_ret;
00218                         MUTEX_LOCK(dbenv, dblp->mtx_dbreg);
00219                 }
00220 
00221                 dblp->dbentry[i].deleted = 0;
00222                 dblp->dbentry[i].dbp = NULL;
00223         }
00224         MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg);
00225         return (ret);
00226 }
00227 
00228 /*
00229  * __dbreg_id_to_db --
00230  *      Return the DB corresponding to the specified dbreg id.
00231  *
00232  * PUBLIC: int __dbreg_id_to_db __P((DB_ENV *, DB_TXN *, DB **, int32_t, int));
00233  */
00234 int
00235 __dbreg_id_to_db(dbenv, txn, dbpp, ndx, inc)
00236         DB_ENV *dbenv;
00237         DB_TXN *txn;
00238         DB **dbpp;
00239         int32_t ndx;
00240         int inc;
00241 {
00242         return (__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, 1));
00243 }
00244 
00245 /*
00246  * __dbreg_id_to_db_int --
00247  *      Return the DB corresponding to the specified dbreg id.  The internal
00248  * version takes a final parameter that indicates whether we should attempt
00249  * to open the file if no mapping is found.  During recovery, the recovery
00250  * routines all want to try to open the file (and this is called from
00251  * __dbreg_id_to_db), however, if we have a multi-process environment where
00252  * some processes may not have the files open (e.g., XA), then we also get
00253  * called from __dbreg_assign_id and it's OK if there is no mapping.
00254  *
00255  * PUBLIC: int __dbreg_id_to_db_int __P((DB_ENV *,
00256  * PUBLIC:     DB_TXN *, DB **, int32_t, int, int));
00257  */
00258 int
00259 __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen)
00260         DB_ENV *dbenv;
00261         DB_TXN *txn;
00262         DB **dbpp;
00263         int32_t ndx;
00264         int inc, tryopen;
00265 {
00266         DB_LOG *dblp;
00267         FNAME *fname;
00268         int ret;
00269         char *name;
00270 
00271         ret = 0;
00272         dblp = dbenv->lg_handle;
00273         COMPQUIET(inc, 0);
00274 
00275         MUTEX_LOCK(dbenv, dblp->mtx_dbreg);
00276 
00277         /*
00278          * Under XA, a process different than the one issuing DB operations
00279          * may abort a transaction.  In this case, the "recovery" routines
00280          * are run by a process that does not necessarily have the file open,
00281          * so we we must open the file explicitly.
00282          */
00283         if (ndx >= dblp->dbentry_cnt ||
00284             (!dblp->dbentry[ndx].deleted && dblp->dbentry[ndx].dbp == NULL)) {
00285                 if (!tryopen || F_ISSET(dblp, DBLOG_RECOVER)) {
00286                         ret = ENOENT;
00287                         goto err;
00288                 }
00289 
00290                 /*
00291                  * __dbreg_id_to_fname acquires the mtx_filelist mutex, which
00292                  * we can't safely acquire while we hold the thread lock.  We
00293                  * no longer need it anyway--the dbentry table didn't have what
00294                  * we needed.
00295                  */
00296                 MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg);
00297 
00298                 if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0)
00299                         /*
00300                          * With transactional opens, we may actually have
00301                          * closed this file in the transaction in which
00302                          * case this will fail too.  Then it's up to the
00303                          * caller to reopen the file.
00304                          */
00305                         return (ENOENT);
00306 
00307                 /*
00308                  * Note that we're relying on fname not to change, even though
00309                  * we released the mutex that protects it (mtx_filelist) inside
00310                  * __dbreg_id_to_fname.  This should be a safe assumption, the
00311                  * other process that has the file open shouldn't be closing it
00312                  * while we're trying to abort.
00313                  */
00314                 name = R_ADDR(&dblp->reginfo, fname->name_off);
00315 
00316                 /*
00317                  * At this point, we are not holding the thread lock, so exit
00318                  * directly instead of going through the exit code at the
00319                  * bottom.  If the __dbreg_do_open succeeded, then we don't need
00320                  * to do any of the remaining error checking at the end of this
00321                  * routine.
00322                  * XXX I am sending a NULL txnlist and 0 txnid which may be
00323                  * completely broken ;(
00324                  */
00325                 if ((ret = __dbreg_do_open(dbenv, txn, dblp,
00326                     fname->ufid, name, fname->s_type,
00327                     ndx, fname->meta_pgno, NULL, 0, DBREG_OPEN)) != 0)
00328                         return (ret);
00329 
00330                 *dbpp = dblp->dbentry[ndx].dbp;
00331                 return (0);
00332         }
00333 
00334         /*
00335          * Return DB_DELETED if the file has been deleted (it's not an error).
00336          */
00337         if (dblp->dbentry[ndx].deleted) {
00338                 ret = DB_DELETED;
00339                 goto err;
00340         }
00341 
00342         /* It's an error if we don't have a corresponding writeable DB. */
00343         if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL)
00344                 ret = ENOENT;
00345         else
00346                 /*
00347                  * If we are in recovery, then set that the file has
00348                  * been written.  It is possible to run recovery,
00349                  * find all the pages in their post update state
00350                  * in the OS buffer pool, put a checkpoint in the log
00351                  * and then crash the system without forcing the pages
00352                  * to disk. If this is an in-memory file, we may not have
00353                  * an mpf yet.
00354                  */
00355                 if ((*dbpp)->mpf != NULL && (*dbpp)->mpf->mfp != NULL)
00356                         (*dbpp)->mpf->mfp->file_written = 1;
00357 
00358 err:    MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg);
00359         return (ret);
00360 }
00361 
00362 /*
00363  * __dbreg_id_to_fname --
00364  *      Traverse the shared-memory region looking for the entry that
00365  *      matches the passed dbreg id.  Returns 0 on success; -1 on error.
00366  *
00367  * PUBLIC: int __dbreg_id_to_fname __P((DB_LOG *, int32_t, int, FNAME **));
00368  */
00369 int
00370 __dbreg_id_to_fname(dblp, id, have_lock, fnamep)
00371         DB_LOG *dblp;
00372         int32_t id;
00373         int have_lock;
00374         FNAME **fnamep;
00375 {
00376         DB_ENV *dbenv;
00377         FNAME *fnp;
00378         LOG *lp;
00379         int ret;
00380 
00381         dbenv = dblp->dbenv;
00382         lp = dblp->reginfo.primary;
00383 
00384         ret = -1;
00385 
00386         if (!have_lock)
00387                 MUTEX_LOCK(dbenv, lp->mtx_filelist);
00388         for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00389             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
00390                 if (fnp->id == id) {
00391                         *fnamep = fnp;
00392                         ret = 0;
00393                         break;
00394                 }
00395         }
00396         if (!have_lock)
00397                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00398 
00399         return (ret);
00400 }
00401 /*
00402  * __dbreg_fid_to_fname --
00403  *      Traverse the shared-memory region looking for the entry that
00404  *      matches the passed file unique id.  Returns 0 on success; -1 on error.
00405  *
00406  * PUBLIC: int __dbreg_fid_to_fname __P((DB_LOG *, u_int8_t *, int, FNAME **));
00407  */
00408 int
00409 __dbreg_fid_to_fname(dblp, fid, have_lock, fnamep)
00410         DB_LOG *dblp;
00411         u_int8_t *fid;
00412         int have_lock;
00413         FNAME **fnamep;
00414 {
00415         DB_ENV *dbenv;
00416         FNAME *fnp;
00417         LOG *lp;
00418         int ret;
00419 
00420         dbenv = dblp->dbenv;
00421         lp = dblp->reginfo.primary;
00422 
00423         ret = -1;
00424 
00425         if (!have_lock)
00426                 MUTEX_LOCK(dbenv, lp->mtx_filelist);
00427         for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00428             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
00429                 if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) {
00430                         *fnamep = fnp;
00431                         ret = 0;
00432                         break;
00433                 }
00434         }
00435         if (!have_lock)
00436                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00437 
00438         return (ret);
00439 }
00440 
00441 /*
00442  * __dbreg_get_name
00443  *
00444  * Interface to get name of registered files.  This is mainly diagnostic
00445  * and the name passed could be transient unless there is something
00446  * ensuring that the file cannot be closed.
00447  *
00448  * PUBLIC: int __dbreg_get_name __P((DB_ENV *, u_int8_t *, char **));
00449  */
00450 int
00451 __dbreg_get_name(dbenv, fid, namep)
00452         DB_ENV *dbenv;
00453         u_int8_t *fid;
00454         char **namep;
00455 {
00456         DB_LOG *dblp;
00457         FNAME *fnp;
00458 
00459         dblp = dbenv->lg_handle;
00460 
00461         if (dblp != NULL && __dbreg_fid_to_fname(dblp, fid, 0, &fnp) == 0) {
00462                 *namep = R_ADDR(&dblp->reginfo, fnp->name_off);
00463                 return (0);
00464         }
00465 
00466         return (-1);
00467 }
00468 
00469 /*
00470  * __dbreg_do_open --
00471  *      Open files referenced in the log.  This is the part of the open that
00472  * is not protected by the thread mutex.
00473  * PUBLIC: int __dbreg_do_open __P((DB_ENV *, DB_TXN *, DB_LOG *, u_int8_t *,
00474  * PUBLIC:     char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t,
00475  * PUBLIC:     u_int32_t));
00476  */
00477 int
00478 __dbreg_do_open(dbenv,
00479     txn, lp, uid, name, ftype, ndx, meta_pgno, info, id, opcode)
00480         DB_ENV *dbenv;
00481         DB_TXN *txn;
00482         DB_LOG *lp;
00483         u_int8_t *uid;
00484         char *name;
00485         DBTYPE ftype;
00486         int32_t ndx;
00487         db_pgno_t meta_pgno;
00488         void *info;
00489         u_int32_t id, opcode;
00490 {
00491         DB *dbp;
00492         u_int32_t cstat, ret_stat;
00493         int ret;
00494         char *dname, *fname;
00495 
00496         cstat = TXN_EXPECTED;
00497         fname = name;
00498         dname = NULL;
00499         if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0)
00500                 return (ret);
00501 
00502         /*
00503          * We can open files under a number of different scenarios.
00504          * First, we can open a file during a normal txn_abort, if that file
00505          * was opened and closed during the transaction (as is the master
00506          * database of a sub-database).
00507          * Second, we might be aborting a transaction in XA and not have
00508          * it open in the process that is actually doing the abort.
00509          * Third, we might be in recovery.
00510          * In case 3, there is no locking, so there is no issue.
00511          * In cases 1 and 2, we are guaranteed to already hold any locks
00512          * that we need, since we're still in the same transaction, so by
00513          * setting DB_AM_RECOVER, we guarantee that we don't log and that
00514          * we don't try to acquire locks on behalf of a different locker id.
00515          */
00516         F_SET(dbp, DB_AM_RECOVER);
00517         if (meta_pgno != PGNO_BASE_MD) {
00518                 memcpy(dbp->fileid, uid, DB_FILE_ID_LEN);
00519                 dbp->meta_pgno = meta_pgno;
00520         }
00521         if (opcode == DBREG_PREOPEN) {
00522                 dbp->type = ftype;
00523                 if ((ret = __dbreg_setup(dbp, name, id)) != 0)
00524                         goto err;
00525                 MAKE_INMEM(dbp);
00526                 goto skip_open;
00527         }
00528 
00529         if (opcode == DBREG_REOPEN) {
00530                 MAKE_INMEM(dbp);
00531                 fname = NULL;
00532                 dname = name;
00533         }
00534 
00535         if ((ret = __db_open(dbp, txn, fname, dname, ftype,
00536             DB_DURABLE_UNKNOWN | DB_ODDFILESIZE,
00537             __db_omode(OWNER_RW), meta_pgno)) == 0) {
00538 skip_open:
00539                 /*
00540                  * Verify that we are opening the same file that we were
00541                  * referring to when we wrote this log record.
00542                  */
00543                 if ((meta_pgno != PGNO_BASE_MD &&
00544                     __dbreg_check_master(dbenv, uid, name) != 0) ||
00545                     memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
00546                         cstat = TXN_UNEXPECTED;
00547                 else
00548                         cstat = TXN_EXPECTED;
00549 
00550                 /* Assign the specific dbreg id to this dbp. */
00551                 if ((ret = __dbreg_assign_id(dbp, ndx)) != 0)
00552                         goto err;
00553 
00554                 /*
00555                  * If we successfully opened this file, then we need to
00556                  * convey that information to the txnlist so that we
00557                  * know how to handle the subtransaction that created
00558                  * the file system object.
00559                  */
00560                 if (id != TXN_INVALID)
00561                         ret = __db_txnlist_update(dbenv,
00562                             info, id, cstat, NULL, &ret_stat, 1);
00563 
00564 err:            if (cstat == TXN_UNEXPECTED)
00565                         goto not_right;
00566                 return (ret);
00567         } else if (ret == ENOENT) {
00568                 /* Record that the open failed in the txnlist. */
00569                 if (id != TXN_INVALID)
00570                         ret = __db_txnlist_update(dbenv, info,
00571                             id, TXN_UNEXPECTED, NULL, &ret_stat, 1);
00572         }
00573 not_right:
00574         (void)__db_close(dbp, NULL, DB_NOSYNC);
00575         /* Add this file as deleted. */
00576         (void)__dbreg_add_dbentry(dbenv, lp, NULL, ndx);
00577         return (ret);
00578 }
00579 
00580 static int
00581 __dbreg_check_master(dbenv, uid, name)
00582         DB_ENV *dbenv;
00583         u_int8_t *uid;
00584         char *name;
00585 {
00586         DB *dbp;
00587         int ret;
00588 
00589         ret = 0;
00590         if ((ret = db_create(&dbp, dbenv, 0)) != 0)
00591                 return (ret);
00592         F_SET(dbp, DB_AM_RECOVER);
00593         ret = __db_open(dbp, NULL,
00594             name, NULL, DB_BTREE, 0, __db_omode(OWNER_RW), PGNO_BASE_MD);
00595 
00596         if (ret == 0 && memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
00597                 ret = EINVAL;
00598 
00599         (void)__db_close(dbp, NULL, 0);
00600         return (ret);
00601 }
00602 
00603 /*
00604  * __dbreg_lazy_id --
00605  *      When a replication client gets upgraded to being a replication master,
00606  * it may have database handles open that have not been assigned an ID, but
00607  * which have become legal to use for logging.
00608  *
00609  *      This function lazily allocates a new ID for such a function, in a
00610  * new transaction created for the purpose.  We need to do this in a new
00611  * transaction because we definitely wish to commit the dbreg_register, but
00612  * at this point we have no way of knowing whether the log record that incited
00613  * us to call this will be part of a committed transaction.
00614  *
00615  * PUBLIC: int __dbreg_lazy_id __P((DB *));
00616  */
00617 int
00618 __dbreg_lazy_id(dbp)
00619         DB *dbp;
00620 {
00621         DB_ENV *dbenv;
00622         DB_LOG *dblp;
00623         DB_TXN *txn;
00624         FNAME *fnp;
00625         LOG *lp;
00626         int32_t id;
00627         int ret;
00628 
00629         dbenv = dbp->dbenv;
00630 
00631         DB_ASSERT(IS_REP_MASTER(dbenv));
00632 
00633         dbenv = dbp->dbenv;
00634         dblp = dbenv->lg_handle;
00635         lp = dblp->reginfo.primary;
00636         fnp = dbp->log_filename;
00637 
00638         /* The mtx_filelist protects the FNAME list and id management. */
00639         MUTEX_LOCK(dbenv, lp->mtx_filelist);
00640         if (fnp->id != DB_LOGFILEID_INVALID) {
00641                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00642                 return (0);
00643         }
00644         id = DB_LOGFILEID_INVALID;
00645         if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00646                 goto err;
00647 
00648         if ((ret = __dbreg_get_id(dbp, txn, &id)) != 0) {
00649                 (void)__txn_abort(txn);
00650                 goto err;
00651         }
00652 
00653         if ((ret = __txn_commit(txn, DB_TXN_NOSYNC)) != 0)
00654                 goto err;
00655 
00656         /*
00657          * All DB related logging routines check the id value *without*
00658          * holding the mtx_filelist to know whether we need to call
00659          * dbreg_lazy_id to begin with.  We must set the ID after a
00660          * *successful* commit so that there is no possibility of a second
00661          * modification call finding a valid ID in the dbp before the
00662          * dbreg_register and commit records are in the log.
00663          * If there was an error, then we call __dbreg_revoke_id to
00664          * remove the entry from the lists.
00665          */
00666         fnp->id = id;
00667 err:
00668         if (ret != 0 && id != DB_LOGFILEID_INVALID)
00669                 (void)__dbreg_revoke_id(dbp, 1, id);
00670         MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00671         return (ret);
00672 }

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