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

dbreg.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: dbreg.c,v 12.12 2005/10/14 14:40:41 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/log.h"
00021 #include "dbinc/txn.h"
00022 #include "dbinc/db_am.h"
00023 
00024 static int __dbreg_push_id __P((DB_ENV *, DB *, int32_t));
00025 static int __dbreg_pop_id __P((DB_ENV *, int32_t *));
00026 static int __dbreg_pluck_id __P((DB_ENV *, int32_t));
00027 
00028 /*
00029  * The dbreg subsystem, as its name implies, registers database handles so
00030  * that we can associate log messages with them without logging a filename
00031  * or a full, unique DB ID.  Instead, we assign each dbp an int32_t which is
00032  * easy and cheap to log, and use this subsystem to map back and forth.
00033  *
00034  * Overview of how dbreg ids are managed:
00035  *
00036  * OPEN
00037  *      dbreg_setup (Creates FNAME struct.)
00038  *      dbreg_new_id (Assigns new ID to dbp and logs it.  May be postponed
00039  *      until we attempt to log something else using that dbp, if the dbp
00040  *      was opened on a replication client.)
00041  *
00042  * CLOSE
00043  *      dbreg_close_id  (Logs closure of dbp/revocation of ID.)
00044  *      dbreg_revoke_id (As name implies, revokes ID.)
00045  *      dbreg_teardown (Destroys FNAME.)
00046  *
00047  * RECOVERY
00048  *      dbreg_setup
00049  *      dbreg_assign_id (Assigns a particular ID we have in the log to a dbp.)
00050  *
00051  *      sometimes: dbreg_revoke_id; dbreg_teardown
00052  *      other times: normal close path
00053  *
00054  * A note about locking:
00055  *
00056  *      FNAME structures are referenced only by their corresponding dbp's
00057  *      until they have a valid id.
00058  *
00059  *      Once they have a valid id, they must get linked into the log
00060  *      region list so they can get logged on checkpoints.
00061  *
00062  *      An FNAME that may/does have a valid id must be accessed under
00063  *      protection of the mtx_filelist, with the following exception:
00064  *
00065  *      We don't want to have to grab the mtx_filelist on every log
00066  *      record, and it should be safe not to do so when we're just
00067  *      looking at the id, because once allocated, the id should
00068  *      not change under a handle until the handle is closed.
00069  *
00070  *      If a handle is closed during an attempt by another thread to
00071  *      log with it, well, the application doing the close deserves to
00072  *      go down in flames and a lot else is about to fail anyway.
00073  *
00074  *      When in the course of logging we encounter an invalid id
00075  *      and go to allocate it lazily, we *do* need to check again
00076  *      after grabbing the mutex, because it's possible to race with
00077  *      another thread that has also decided that it needs to allocate
00078  *      a id lazily.
00079  *
00080  * See SR #5623 for further discussion of the new dbreg design.
00081  */
00082 
00083 /*
00084  * __dbreg_setup --
00085  *      Allocate and initialize an FNAME structure.  The FNAME structures
00086  * live in the log shared region and map one-to-one with open database handles.
00087  * When the handle needs to be logged, the FNAME should have a valid fid
00088  * allocated.  If the handle currently isn't logged, it still has an FNAME
00089  * entry.  If we later discover that the handle needs to be logged, we can
00090  * allocate a id for it later.  (This happens when the handle is on a
00091  * replication client that later becomes a master.)
00092  *
00093  * PUBLIC: int __dbreg_setup __P((DB *, const char *, u_int32_t));
00094  */
00095 int
00096 __dbreg_setup(dbp, name, create_txnid)
00097         DB *dbp;
00098         const char *name;
00099         u_int32_t create_txnid;
00100 {
00101         DB_ENV *dbenv;
00102         DB_LOG *dblp;
00103         FNAME *fnp;
00104         REGINFO *infop;
00105         int ret;
00106         size_t len;
00107         void *namep;
00108 
00109         dbenv = dbp->dbenv;
00110         dblp = dbenv->lg_handle;
00111         infop = &dblp->reginfo;
00112 
00113         fnp = NULL;
00114         namep = NULL;
00115 
00116         /* Allocate an FNAME and, if necessary, a buffer for the name itself. */
00117         LOG_SYSTEM_LOCK(dbenv);
00118         if ((ret = __db_shalloc(infop, sizeof(FNAME), 0, &fnp)) != 0)
00119                 goto err;
00120         memset(fnp, 0, sizeof(FNAME));
00121         if (name != NULL) {
00122                 len = strlen(name) + 1;
00123                 if ((ret = __db_shalloc(infop, len, 0, &namep)) != 0)
00124                         goto err;
00125                 fnp->name_off = R_OFFSET(infop, namep);
00126                 memcpy(namep, name, len);
00127         } else
00128                 fnp->name_off = INVALID_ROFF;
00129 
00130         LOG_SYSTEM_UNLOCK(dbenv);
00131 
00132         /*
00133          * Fill in all the remaining info that we'll need later to register
00134          * the file, if we use it for logging.
00135          */
00136         fnp->id = DB_LOGFILEID_INVALID;
00137         fnp->s_type = dbp->type;
00138         memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
00139         fnp->meta_pgno = dbp->meta_pgno;
00140         fnp->create_txnid = create_txnid;
00141 
00142         dbp->log_filename = fnp;
00143 
00144         return (0);
00145 
00146 err:    LOG_SYSTEM_UNLOCK(dbenv);
00147         if (ret == ENOMEM)
00148                 __db_err(dbenv,
00149     "Logging region out of memory; you may need to increase its size");
00150 
00151         return (ret);
00152 }
00153 
00154 /*
00155  * __dbreg_teardown --
00156  *      Destroy a DB handle's FNAME struct.
00157  *
00158  * PUBLIC: int __dbreg_teardown __P((DB *));
00159  */
00160 int
00161 __dbreg_teardown(dbp)
00162         DB *dbp;
00163 {
00164         DB_ENV *dbenv;
00165         DB_LOG *dblp;
00166         REGINFO *infop;
00167         FNAME *fnp;
00168 
00169         dbenv = dbp->dbenv;
00170         dblp = dbenv->lg_handle;
00171         infop = &dblp->reginfo;
00172         fnp = dbp->log_filename;
00173 
00174         /*
00175          * We may not have an FNAME if we were never opened.  This is not an
00176          * error.
00177          */
00178         if (fnp == NULL || F_ISSET(fnp, DB_FNAME_NOTLOGGED))
00179                 return (0);
00180 
00181         DB_ASSERT(fnp->id == DB_LOGFILEID_INVALID);
00182 
00183         LOG_SYSTEM_LOCK(dbenv);
00184         if (fnp->name_off != INVALID_ROFF)
00185                 __db_shalloc_free(infop, R_ADDR(infop, fnp->name_off));
00186         __db_shalloc_free(infop, fnp);
00187         LOG_SYSTEM_UNLOCK(dbenv);
00188 
00189         dbp->log_filename = NULL;
00190 
00191         return (0);
00192 }
00193 
00194 /*
00195  * __dbreg_new_id --
00196  *      Get an unused dbreg id to this database handle.
00197  *      Used as a wrapper to acquire the mutex and
00198  *      only set the id on success.
00199  *
00200  * PUBLIC: int __dbreg_new_id __P((DB *, DB_TXN *));
00201  */
00202 int
00203 __dbreg_new_id(dbp, txn)
00204         DB *dbp;
00205         DB_TXN *txn;
00206 {
00207         DB_ENV *dbenv;
00208         DB_LOG *dblp;
00209         FNAME *fnp;
00210         LOG *lp;
00211         int32_t id;
00212         int ret;
00213 
00214         dbenv = dbp->dbenv;
00215         dblp = dbenv->lg_handle;
00216         lp = dblp->reginfo.primary;
00217         fnp = dbp->log_filename;
00218 
00219         /* The mtx_filelist protects the FNAME list and id management. */
00220         MUTEX_LOCK(dbenv, lp->mtx_filelist);
00221         if (fnp->id != DB_LOGFILEID_INVALID) {
00222                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00223                 return (0);
00224         }
00225         if ((ret = __dbreg_get_id(dbp, txn, &id)) == 0)
00226                 fnp->id = id;
00227         MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00228         return (ret);
00229 }
00230 
00231 /*
00232  * __dbreg_get_id --
00233  *      Assign an unused dbreg id to this database handle.
00234  *      Assume the caller holds the mtx_filelist locked.  Assume the
00235  *      caller will set the fnp->id field with the id we return.
00236  *
00237  * PUBLIC: int __dbreg_get_id __P((DB *, DB_TXN *, int32_t *));
00238  */
00239 int
00240 __dbreg_get_id(dbp, txn, idp)
00241         DB *dbp;
00242         DB_TXN *txn;
00243         int32_t *idp;
00244 {
00245         DB_ENV *dbenv;
00246         DB_LOG *dblp;
00247         FNAME *fnp;
00248         LOG *lp;
00249         int32_t id;
00250         int ret;
00251 
00252         dbenv = dbp->dbenv;
00253         dblp = dbenv->lg_handle;
00254         lp = dblp->reginfo.primary;
00255         fnp = dbp->log_filename;
00256 
00257         /*
00258          * It's possible that after deciding we needed to call this function,
00259          * someone else allocated an ID before we grabbed the lock.  Check
00260          * to make sure there was no race and we have something useful to do.
00261          */
00262         /* Get an unused ID from the free list. */
00263         if ((ret = __dbreg_pop_id(dbenv, &id)) != 0)
00264                 goto err;
00265 
00266         /* If no ID was found, allocate a new one. */
00267         if (id == DB_LOGFILEID_INVALID)
00268                 id = lp->fid_max++;
00269 
00270         /* If the file is durable (i.e., not, not-durable), mark it as such. */
00271         if (!F_ISSET(dbp, DB_AM_NOT_DURABLE))
00272                 F_SET(fnp, DB_FNAME_DURABLE);
00273 
00274         /* Hook the FNAME into the list of open files. */
00275         SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname);
00276 
00277         /*
00278          * Log the registry.  We should only request a new ID in situations
00279          * where logging is reasonable.
00280          */
00281         DB_ASSERT(!F_ISSET(dbp, DB_AM_RECOVER));
00282 
00283         if ((ret = __dbreg_log_id(dbp, txn, id, 0)) != 0)
00284                 goto err;
00285 
00286         /*
00287          * Once we log the create_txnid, we need to make sure we never
00288          * log it again (as might happen if this is a replication client
00289          * that later upgrades to a master).
00290          */
00291         fnp->create_txnid = TXN_INVALID;
00292 
00293         DB_ASSERT(dbp->type == fnp->s_type);
00294         DB_ASSERT(dbp->meta_pgno == fnp->meta_pgno);
00295 
00296         if ((ret = __dbreg_add_dbentry(dbenv, dblp, dbp, id)) != 0)
00297                 goto err;
00298         /*
00299          * If we have a successful call, set the ID.  Otherwise
00300          * we have to revoke it and remove it from all the lists
00301          * it has been added to, and return an invalid id.
00302          */
00303 err:
00304         if (ret != 0 && id != DB_LOGFILEID_INVALID) {
00305                 (void)__dbreg_revoke_id(dbp, 1, id);
00306                 id = DB_LOGFILEID_INVALID;
00307         }
00308         *idp = id;
00309         return (ret);
00310 }
00311 
00312 /*
00313  * __dbreg_assign_id --
00314  *      Assign a particular dbreg id to this database handle.
00315  *
00316  * PUBLIC: int __dbreg_assign_id __P((DB *, int32_t));
00317  */
00318 int
00319 __dbreg_assign_id(dbp, id)
00320         DB *dbp;
00321         int32_t id;
00322 {
00323         DB *close_dbp;
00324         DB_ENV *dbenv;
00325         DB_LOG *dblp;
00326         FNAME *close_fnp, *fnp;
00327         LOG *lp;
00328         int ret;
00329 
00330         dbenv = dbp->dbenv;
00331         dblp = dbenv->lg_handle;
00332         lp = dblp->reginfo.primary;
00333         fnp = dbp->log_filename;
00334 
00335         close_dbp = NULL;
00336         close_fnp = NULL;
00337 
00338         /* The mtx_filelist protects the FNAME list and id management. */
00339         MUTEX_LOCK(dbenv, lp->mtx_filelist);
00340 
00341         /* We should only call this on DB handles that have no ID. */
00342         DB_ASSERT(fnp->id == DB_LOGFILEID_INVALID);
00343 
00344         /*
00345          * Make sure there isn't already a file open with this ID. There can
00346          * be in recovery, if we're recovering across a point where an ID got
00347          * reused.
00348          */
00349         if (__dbreg_id_to_fname(dblp, id, 1, &close_fnp) == 0) {
00350                 /*
00351                  * We want to save off any dbp we have open with this id.  We
00352                  * can't safely close it now, because we hold the mtx_filelist,
00353                  * but we should be able to rely on it being open in this
00354                  * process, and we're running recovery, so no other thread
00355                  * should muck with it if we just put off closing it until
00356                  * we're ready to return.
00357                  *
00358                  * Once we have the dbp, revoke its id;  we're about to
00359                  * reuse it.
00360                  */
00361                 ret = __dbreg_id_to_db_int(dbenv, NULL, &close_dbp, id, 0, 0);
00362                 if (ret == ENOENT) {
00363                         ret = 0;
00364                         goto cont;
00365                 } else if (ret != 0)
00366                         goto err;
00367 
00368                 if ((ret = __dbreg_revoke_id(close_dbp, 1,
00369                     DB_LOGFILEID_INVALID)) != 0)
00370                         goto err;
00371         }
00372 
00373         /*
00374          * Remove this ID from the free list, if it's there, and make sure
00375          * we don't allocate it anew.
00376          */
00377 cont:   if ((ret = __dbreg_pluck_id(dbenv, id)) != 0)
00378                 goto err;
00379         if (id >= lp->fid_max)
00380                 lp->fid_max = id + 1;
00381 
00382         /* Now go ahead and assign the id to our dbp. */
00383         fnp->id = id;
00384         /* If the file is durable (i.e., not, not-durable), mark it as such. */
00385         if (!F_ISSET(dbp, DB_AM_NOT_DURABLE))
00386                 F_SET(fnp, DB_FNAME_DURABLE);
00387         SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname);
00388 
00389         /*
00390          * If we get an error adding the dbentry, revoke the id.
00391          * We void the return value since we want to retain and
00392          * return the original error in ret anyway.
00393          */
00394         if ((ret = __dbreg_add_dbentry(dbenv, dblp, dbp, id)) != 0)
00395                 (void)__dbreg_revoke_id(dbp, 1, id);
00396 
00397 err:    MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00398 
00399         /* There's nothing useful that our caller can do if this close fails. */
00400         if (close_dbp != NULL)
00401                 (void)__db_close(close_dbp, NULL, DB_NOSYNC);
00402 
00403         return (ret);
00404 }
00405 
00406 /*
00407  * __dbreg_revoke_id --
00408  *      Take a log id away from a dbp, in preparation for closing it,
00409  *      but without logging the close.
00410  *
00411  * PUBLIC: int __dbreg_revoke_id __P((DB *, int, int32_t));
00412  */
00413 int
00414 __dbreg_revoke_id(dbp, have_lock, force_id)
00415         DB *dbp;
00416         int have_lock;
00417         int32_t force_id;
00418 {
00419         DB_ENV *dbenv;
00420         DB_LOG *dblp;
00421         FNAME *fnp;
00422         LOG *lp;
00423         int32_t id;
00424         int ret;
00425 
00426         dbenv = dbp->dbenv;
00427         dblp = dbenv->lg_handle;
00428         lp = dblp->reginfo.primary;
00429         fnp = dbp->log_filename;
00430 
00431         /* If we lack an ID, this is a null-op. */
00432         if (fnp == NULL)
00433                 return (0);
00434 
00435         /*
00436          * If we have a force_id, we had an error after allocating
00437          * the id, and putting it on the fq list, but before we
00438          * finished setting up fnp.  So, if we have a force_id use it.
00439          */
00440         if (force_id != DB_LOGFILEID_INVALID)
00441                 id = force_id;
00442         else if (fnp->id == DB_LOGFILEID_INVALID)
00443                 return (0);
00444         else
00445                 id = fnp->id;
00446         if (!have_lock)
00447                 MUTEX_LOCK(dbenv, lp->mtx_filelist);
00448 
00449         fnp->id = DB_LOGFILEID_INVALID;
00450 
00451         /* Remove the FNAME from the list of open files. */
00452         SH_TAILQ_REMOVE(&lp->fq, fnp, q, __fname);
00453 
00454         /*
00455          * Remove this id from the dbentry table and push it onto the
00456          * free list.
00457          */
00458         if ((ret = __dbreg_rem_dbentry(dblp, id)) == 0) {
00459                 /*
00460                  * If we are not in recovery but the file was opened
00461                  * for a recovery operation, then this process aborted
00462                  * a transaction for another process and the id may
00463                  * still be in use, so don't reuse this id.
00464                  */
00465                 if (!F_ISSET(dbp, DB_AM_RECOVER) || IS_RECOVERING(dbenv))
00466                         ret = __dbreg_push_id(dbenv, dbp, id);
00467         }
00468 
00469         if (!have_lock)
00470                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00471         return (ret);
00472 }
00473 
00474 /*
00475  * __dbreg_close_id --
00476  *      Take a dbreg id away from a dbp that we're closing, and log
00477  * the unregistry.
00478  *
00479  * PUBLIC: int __dbreg_close_id __P((DB *, DB_TXN *, u_int32_t));
00480  */
00481 int
00482 __dbreg_close_id(dbp, txn, op)
00483         DB *dbp;
00484         DB_TXN *txn;
00485         u_int32_t op;
00486 {
00487         DBT fid_dbt, r_name, *dbtp;
00488         DB_ENV *dbenv;
00489         DB_LOG *dblp;
00490         DB_LSN r_unused;
00491         FNAME *fnp;
00492         LOG *lp;
00493         int ret;
00494 
00495         dbenv = dbp->dbenv;
00496         dblp = dbenv->lg_handle;
00497         lp = dblp->reginfo.primary;
00498         fnp = dbp->log_filename;
00499 
00500         /* If we lack an ID, this is a null-op. */
00501         if (fnp == NULL || fnp->id == DB_LOGFILEID_INVALID)
00502                 return (0);
00503 
00504         MUTEX_LOCK(dbenv, lp->mtx_filelist);
00505 
00506         if (fnp->name_off == INVALID_ROFF)
00507                 dbtp = NULL;
00508         else {
00509                 memset(&r_name, 0, sizeof(r_name));
00510                 r_name.data = R_ADDR(&dblp->reginfo, fnp->name_off);
00511                 r_name.size =
00512                     (u_int32_t)strlen((char *)r_name.data) + 1;
00513                 dbtp = &r_name;
00514         }
00515         memset(&fid_dbt, 0, sizeof(fid_dbt));
00516         fid_dbt.data = fnp->ufid;
00517         fid_dbt.size = DB_FILE_ID_LEN;
00518         if ((ret = __dbreg_register_log(dbenv, txn, &r_unused,
00519             F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0,
00520             op, dbtp, &fid_dbt, fnp->id,
00521             fnp->s_type, fnp->meta_pgno, TXN_INVALID)) != 0) {
00522                 /*
00523                  * We are trying to close, but the log write failed.
00524                  * Unfortunately, close needs to plow forward, because
00525                  * the application can't do anything with the handle.
00526                  * Make the entry in the shared memory region so that
00527                  * when we close the environment, we know that this
00528                  * happened.  Also, make sure we remove this from the
00529                  * per-process table, so that we don't try to close it
00530                  * later.
00531                  */
00532                 F_SET(fnp, DB_FNAME_NOTLOGGED);
00533                 (void)__dbreg_rem_dbentry(dblp, fnp->id);
00534                 goto err;
00535         }
00536 
00537         ret = __dbreg_revoke_id(dbp, 1, DB_LOGFILEID_INVALID);
00538 
00539 err:    MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00540         return (ret);
00541 }
00542 
00543 /*
00544  * __dbreg_push_id and __dbreg_pop_id --
00545  *      Dbreg ids from closed files are kept on a stack in shared memory
00546  * for recycling.  (We want to reuse them as much as possible because each
00547  * process keeps open files in an array by ID.)  Push them to the stack and
00548  * pop them from it, managing memory as appropriate.
00549  *
00550  * The stack is protected by the mtx_filelist, and both functions assume it
00551  * is already locked.
00552  */
00553 static int
00554 __dbreg_push_id(dbenv, dbp, id)
00555         DB_ENV *dbenv;
00556         DB *dbp;
00557         int32_t id;
00558 {
00559         DB_LOG *dblp;
00560         DB_REP *db_rep;
00561         LOG *lp;
00562         REGINFO *infop;
00563         int32_t *stack, *newstack;
00564         int ret;
00565 
00566         dblp = dbenv->lg_handle;
00567         infop = &dblp->reginfo;
00568         lp = infop->primary;
00569         db_rep = dbenv->rep_handle;
00570 
00571         /*
00572          * If our fid generation in replication has changed, this fid should
00573          * not be pushed back onto the stack.
00574          */
00575         if (REP_ON(dbenv) && db_rep->region != NULL &&
00576            ((REP *)db_rep->region)->gen != dbp->fid_gen)
00577                 return (0);
00578         /* Check if we have room on the stack. */
00579         if (lp->free_fid_stack == INVALID_ROFF ||
00580             lp->free_fids_alloced <= lp->free_fids + 1) {
00581                 LOG_SYSTEM_LOCK(dbenv);
00582                 if ((ret = __db_shalloc(infop,
00583                     (lp->free_fids_alloced + 20) * sizeof(u_int32_t), 0,
00584                     &newstack)) != 0) {
00585                         LOG_SYSTEM_UNLOCK(dbenv);
00586                         return (ret);
00587                 }
00588 
00589                 if (lp->free_fid_stack != INVALID_ROFF) {
00590                         stack = R_ADDR(infop, lp->free_fid_stack);
00591                         memcpy(newstack, stack,
00592                             lp->free_fids_alloced * sizeof(u_int32_t));
00593                         __db_shalloc_free(infop, stack);
00594                 }
00595                 lp->free_fid_stack = R_OFFSET(infop, newstack);
00596                 lp->free_fids_alloced += 20;
00597                 LOG_SYSTEM_UNLOCK(dbenv);
00598         }
00599 
00600         stack = R_ADDR(infop, lp->free_fid_stack);
00601         stack[lp->free_fids++] = id;
00602         return (0);
00603 }
00604 
00605 static int
00606 __dbreg_pop_id(dbenv, id)
00607         DB_ENV *dbenv;
00608         int32_t *id;
00609 {
00610         DB_LOG *dblp;
00611         LOG *lp;
00612         int32_t *stack;
00613 
00614         dblp = dbenv->lg_handle;
00615         lp = dblp->reginfo.primary;
00616 
00617         /* Do we have anything to pop? */
00618         if (lp->free_fid_stack != INVALID_ROFF && lp->free_fids > 0) {
00619                 stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
00620                 *id = stack[--lp->free_fids];
00621         } else
00622                 *id = DB_LOGFILEID_INVALID;
00623 
00624         return (0);
00625 }
00626 
00627 /*
00628  * __dbreg_pluck_id --
00629  *      Remove a particular dbreg id from the stack of free ids.  This is
00630  * used when we open a file, as in recovery, with a specific ID that might
00631  * be on the stack.
00632  *
00633  * Returns success whether or not the particular id was found, and like
00634  * push and pop, assumes that the mtx_filelist is locked.
00635  */
00636 static int
00637 __dbreg_pluck_id(dbenv, id)
00638         DB_ENV *dbenv;
00639         int32_t id;
00640 {
00641         DB_LOG *dblp;
00642         LOG *lp;
00643         int32_t *stack;
00644         u_int i;
00645 
00646         dblp = dbenv->lg_handle;
00647         lp = dblp->reginfo.primary;
00648 
00649         /* Do we have anything to look at? */
00650         if (lp->free_fid_stack != INVALID_ROFF) {
00651                 stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
00652                 for (i = 0; i < lp->free_fids; i++)
00653                         if (id == stack[i]) {
00654                                 /*
00655                                  * Found it.  Overwrite it with the top
00656                                  * id (which may harmlessly be itself),
00657                                  * and shorten the stack by one.
00658                                  */
00659                                 stack[i] = stack[lp->free_fids - 1];
00660                                 lp->free_fids--;
00661                                 return (0);
00662                         }
00663         }
00664 
00665         return (0);
00666 }
00667 
00668 /*
00669  * __dbreg_log_id --
00670  *      Used for in-memory named files.  They are created in mpool and
00671  * are given id's early in the open process so that we can read and
00672  * create pages in the mpool for the files.  However, at the time that
00673  * the mpf is created, the file may not be fully created and/or its
00674  * meta-data may not be fully known, so we can't do a full dbregister.
00675  * This is a routine exported that will log a complete dbregister
00676  * record that will allow for both recovery and replication.
00677  *
00678  * PUBLIC: int __dbreg_log_id __P((DB *, DB_TXN *, int32_t, int));
00679  */
00680 int
00681 __dbreg_log_id(dbp, txn, id, needlock)
00682         DB *dbp;
00683         DB_TXN *txn;
00684         int32_t id;
00685         int needlock;
00686 {
00687         DBT fid_dbt, r_name;
00688         DB_ENV *dbenv;
00689         DB_LOG *dblp;
00690         DB_LSN unused;
00691         FNAME *fnp;
00692         LOG *lp;
00693         u_int32_t op;
00694         int ret;
00695 
00696         dbenv = dbp->dbenv;
00697         dblp = dbenv->lg_handle;
00698         lp = dblp->reginfo.primary;
00699         fnp = dbp->log_filename;
00700 
00701         /* Verify that the fnp has been initialized. */
00702         if (fnp->s_type == DB_UNKNOWN) {
00703                 memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
00704                 fnp->s_type = dbp->type;
00705         }
00706 
00707         /*
00708          * Log the registry.  We should only request a new ID in situations
00709          * where logging is reasonable.
00710          */
00711         memset(&fid_dbt, 0, sizeof(fid_dbt));
00712         memset(&r_name, 0, sizeof(r_name));
00713 
00714         if (needlock)
00715                 MUTEX_LOCK(dbenv, lp->mtx_filelist);
00716 
00717         if (fnp->name_off != INVALID_ROFF) {
00718                 r_name.data = R_ADDR(&dblp->reginfo, fnp->name_off);
00719                 r_name.size = (u_int32_t)strlen((char *)r_name.data) + 1;
00720         }
00721 
00722         fid_dbt.data = dbp->fileid;
00723         fid_dbt.size = DB_FILE_ID_LEN;
00724 
00725         op = !F_ISSET(dbp, DB_AM_OPEN_CALLED) ? DBREG_PREOPEN :
00726             (F_ISSET(dbp, DB_AM_INMEM) ? DBREG_REOPEN : DBREG_OPEN);
00727         ret = __dbreg_register_log(dbenv, txn, &unused,
00728             F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0,
00729             op, r_name.size == 0 ? NULL : &r_name, &fid_dbt, id,
00730             fnp->s_type, fnp->meta_pgno, fnp->create_txnid);
00731 
00732         if (needlock)
00733                 MUTEX_UNLOCK(dbenv, lp->mtx_filelist);
00734 
00735         return (ret);
00736 }

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