mp_fopen.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 #include "config.h"
00008 
00009 #ifndef lint
00010 static const char revid[] = "$Id: mp__fopen_8c-source.html,v 1.1 2008/06/08 10:20:46 sebdiaz Exp $";
00011 #endif /* not lint */
00012 
00013 #ifndef NO_SYSTEM_INCLUDES
00014 #include <sys/types.h>
00015 
00016 #include <errno.h>
00017 #include <string.h>
00018 #endif
00019 
00020 #ifdef  HAVE_RPC
00021 #include "db_server.h"
00022 #endif
00023 
00024 #include "db_int.h"
00025 #include "db_shash.h"
00026 #include "db_page.h"
00027 #include "mp.h"
00028 
00029 #ifdef HAVE_RPC
00030 #include "gen_client_ext.h"
00031 #include "rpc_client_ext.h"
00032 #endif
00033 
00034 static int __memp_mf_open __P((DB_MPOOL *, const char *,
00035     size_t, db_pgno_t, DB_MPOOL_FINFO *, u_int32_t, MPOOLFILE **));
00036 
00037 /*
00038  * MEMP_FREMOVE --
00039  *      Discard an MPOOLFILE and any buffers it references: update the flags
00040  *      so we never try to write buffers associated with the file, nor can we
00041  *      find it when looking for files to join.  In addition, clear the ftype
00042  *      field, there's no reason to post-process pages, they can be discarded
00043  *      by any thread.
00044  */
00045 #define MEMP_FREMOVE(mfp) {                                             \
00046         mfp->ftype = 0;                                                 \
00047         F_SET(mfp, MP_DEADFILE);                                        \
00048 }
00049 
00050 /*
00051  * CDB_memp_fopen --
00052  *      Open a backing file for the memory pool.
00053  */
00054 int
00055 CDB_memp_fopen(dbenv, path, flags, mode, pagesize, finfop, retp)
00056         DB_ENV *dbenv;
00057         const char *path;
00058         u_int32_t flags;
00059         int mode;
00060         size_t pagesize;
00061         DB_MPOOL_FINFO *finfop;
00062         DB_MPOOLFILE **retp;
00063 {
00064         DB_MPOOL *dbmp;
00065         int ret;
00066 
00067 #ifdef HAVE_RPC
00068         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00069                 return (__dbcl_memp_fopen(dbenv, path, flags,
00070                     mode, pagesize, finfop, retp));
00071 #endif
00072 
00073         PANIC_CHECK(dbenv);
00074         ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL);
00075 
00076         dbmp = dbenv->mp_handle;
00077 
00078         /* Validate arguments. */
00079         if ((ret = CDB___db_fchk(dbenv, "CDB_memp_fopen", flags,
00080             DB_CREATE | DB_COMPRESS |
00081             DB_NOMMAP | DB_ODDFILESIZE | DB_RDONLY | DB_TRUNCATE)) != 0)
00082                 return (ret);
00083         /*
00084          * Transparent I/O compression does not work on mmap'd files.
00085          */
00086         if(LF_ISSET(DB_COMPRESS))
00087           LF_SET(DB_NOMMAP);
00088 
00089         /* Require a non-zero pagesize. */
00090         if (pagesize == 0) {
00091                 CDB___db_err(dbenv, "CDB_memp_fopen: pagesize not specified");
00092                 return (EINVAL);
00093         }
00094         if (finfop != NULL && finfop->clear_len > pagesize)
00095                 return (EINVAL);
00096 
00097         return (CDB___memp_fopen(dbmp,
00098             NULL, path, flags, mode, pagesize, 1, finfop, retp));
00099 }
00100 
00101 /*
00102  * CDB___memp_fopen --
00103  *      Open a backing file for the memory pool; internal version.
00104  *
00105  * PUBLIC: int CDB___memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *,
00106  * PUBLIC:    u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
00107  */
00108 int
00109 CDB___memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
00110         DB_MPOOL *dbmp;
00111         MPOOLFILE *mfp;
00112         const char *path;
00113         u_int32_t flags;
00114         int mode, needlock;
00115         size_t pagesize;
00116         DB_MPOOL_FINFO *finfop;
00117         DB_MPOOLFILE **retp;
00118 {
00119         DB_ENV *dbenv;
00120         DB_MPOOLFILE *dbmfp;
00121         DB_MPOOL_FINFO finfo;
00122         db_pgno_t last_pgno;
00123         size_t maxmap;
00124         u_int32_t mbytes, bytes, oflags;
00125         int ret;
00126         u_int8_t idbuf[DB_FILE_ID_LEN];
00127         char *rpath;
00128 
00129         dbenv = dbmp->dbenv;
00130         ret = 0;
00131         rpath = NULL;
00132 
00133         /*
00134          * If mfp is provided, we take the DB_MPOOL_FINFO information from
00135          * the mfp.  We don't bother initializing everything, because some
00136          * of them are expensive to acquire.  If no mfp is provided and the
00137          * finfop argument is NULL, we default the values.
00138          */
00139         if (finfop == NULL) {
00140                 memset(&finfo, 0, sizeof(finfo));
00141                 if (mfp != NULL) {
00142                         finfo.ftype = mfp->ftype;
00143                         finfo.pgcookie = NULL;
00144                         finfo.fileid = NULL;
00145                         finfo.lsn_offset = mfp->lsn_off;
00146                         finfo.clear_len = mfp->clear_len;
00147                 } else {
00148                         finfo.ftype = 0;
00149                         finfo.pgcookie = NULL;
00150                         finfo.fileid = NULL;
00151                         finfo.lsn_offset = -1;
00152                         finfo.clear_len = 0;
00153                 }
00154                 finfop = &finfo;
00155         }
00156 
00157         /* Allocate and initialize the per-process structure. */
00158         if ((ret = CDB___os_calloc(dbenv, 1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0)
00159                 return (ret);
00160         dbmfp->dbmp = dbmp;
00161         dbmfp->ref = 1;
00162         if (LF_ISSET(DB_RDONLY))
00163                 F_SET(dbmfp, MP_READONLY);
00164         if (LF_ISSET(DB_COMPRESS))
00165                 F_SET(dbmfp, MP_CMPR);
00166 
00167         if (path == NULL) {
00168                 if (LF_ISSET(DB_RDONLY)) {
00169                         CDB___db_err(dbenv,
00170                             "CDB_memp_fopen: temporary files can't be readonly");
00171                         ret = EINVAL;
00172                         goto err;
00173                 }
00174                 if (LF_ISSET(DB_COMPRESS)) {
00175                         CDB___db_err(dbenv,
00176                             "CDB_memp_fopen: temporary files can't be compressed");
00177                         ret = EINVAL;
00178                         goto err;
00179                 }
00180                 last_pgno = PGNO_BASE_MD;
00181         } else {
00182                size_t disk_pagesize = F_ISSET(dbmfp, MP_CMPR) ? DB_CMPR_DIVIDE(dbenv, pagesize) : pagesize;
00183                 /* Get the real name for this file and open it. */
00184                 if ((ret = CDB___db_appname(dbenv,
00185                     DB_APP_DATA, NULL, path, 0, NULL, &rpath)) != 0)
00186                         goto err;
00187                 oflags = 0;
00188                 if (LF_ISSET(DB_CREATE))
00189                         oflags |= DB_OSO_CREATE;
00190                 if (LF_ISSET(DB_RDONLY))
00191                         oflags |= DB_OSO_RDONLY;
00192                 if ((ret =
00193                    CDB___os_open(dbenv, rpath, oflags, mode, &dbmfp->fh)) != 0) {
00194                         CDB___db_err(dbenv, "%s: %s", rpath, CDB_db_strerror(ret));
00195                         goto err;
00196                 }
00197 
00198                 /*
00199                  * Don't permit files that aren't a multiple of the pagesize,
00200                  * and find the number of the last page in the file, all the
00201                  * time being careful not to overflow 32 bits.
00202                  *
00203                  * !!!
00204                  * We can't use off_t's here, or in any code in the mainline
00205                  * library for that matter.  (We have to use them in the os
00206                  * stubs, of course, as there are system calls that take them
00207                  * as arguments.)  The reason is that some customers build in
00208                  * environments where an off_t is 32-bits, but still run where
00209                  * offsets are 64-bits, and they pay us a lot of money.
00210                  */
00211                 if ((ret = CDB___os_ioinfo(dbenv, rpath,
00212                     &dbmfp->fh, &mbytes, &bytes, NULL)) != 0) {
00213                         CDB___db_err(dbenv, "%s: %s", rpath, CDB_db_strerror(ret));
00214                         goto err;
00215                 }
00216 
00217                 /*
00218                  * If we're doing a verify, we might have to cope with
00219                  * a truncated file;  if the file size is not a multiple
00220                  * of the page size, round down to a page--we'll
00221                  * take care of the partial page outside the memp system.
00222                  */
00223 
00224                 /* Page sizes have to be a power-of-two, ignore mbytes. */
00225                 if (bytes % disk_pagesize != 0) {
00226                         if (LF_ISSET(DB_ODDFILESIZE))
00227                                 /*
00228                                  * If we're doing a verify, we might
00229                                  * have to cope with a truncated file;
00230                                  * round down, we'll worry about the partial
00231                                  * page outside the memp system.
00232                                  */
00233                                 bytes -= (bytes % disk_pagesize);
00234                         else {
00235                                 CDB___db_err(dbenv,
00236                 "%s: file size not a multiple of the pagesize",
00237                                     rpath);
00238                                 ret = EINVAL;
00239                                 goto err;
00240                         }
00241                 }
00242 
00243                 last_pgno = mbytes * (MEGABYTE / disk_pagesize);
00244                 last_pgno += bytes / disk_pagesize;
00245 
00246                 /* Correction: page numbers are zero-based, not 1-based. */
00247                 if (last_pgno != 0)
00248                         --last_pgno;
00249                 else
00250                   last_pgno = PGNO_BASE_MD;
00251 
00252                 /*
00253                  * Get the file id if we weren't given one.  Generated file id's
00254                  * don't use timestamps, otherwise there'd be no chance of any
00255                  * other process joining the party.
00256                  */
00257                 if (finfop->fileid == NULL) {
00258                         if ((ret = CDB___os_fileid(dbenv, rpath, 0, idbuf)) != 0)
00259                                 goto err;
00260                         finfop->fileid = idbuf;
00261                 }
00262         }
00263 
00264         /*
00265          * If we weren't provided an underlying shared object to join with,
00266          * find/allocate the shared file objects.  Also allocate space for
00267          * for the per-process thread lock.
00268          */
00269         if (needlock)
00270                 R_LOCK(dbenv, dbmp->reginfo);
00271         ret = mfp == NULL ? __memp_mf_open(
00272             dbmp, path, pagesize, last_pgno, finfop, flags, &mfp) : 0;
00273         if (needlock)
00274                 R_UNLOCK(dbenv, dbmp->reginfo);
00275         if (ret != 0)
00276                 goto err;
00277 
00278         if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00279                 if ((ret = CDB___db_mutex_alloc(
00280                     dbenv, dbmp->reginfo, &dbmfp->mutexp)) != 0)
00281                         goto err;
00282                 if ((ret = __db_mutex_init(
00283                     dbenv, dbmfp->mutexp, 0, MUTEX_THREAD)) != 0)
00284                         goto err;
00285 
00286                 /* XXX: KEITH: CLOSE THE FILE ON FAILURE? */
00287         }
00288 
00289         dbmfp->mfp = mfp;
00290 
00291         /*
00292          * If a file:
00293          *      + is read-only
00294          *      + isn't temporary
00295          *      + doesn't require any pgin/pgout support
00296          *      + the DB_NOMMAP flag wasn't set (in either the file open or
00297          *        the environment in which it was opened)
00298          *      + and is less than mp_mmapsize bytes in size
00299          *
00300          * we can mmap it instead of reading/writing buffers.  Don't do error
00301          * checking based on the mmap call failure.  We want to do normal I/O
00302          * on the file if the reason we failed was because the file was on an
00303          * NFS mounted partition, and we can fail in buffer I/O just as easily
00304          * as here.
00305          *
00306          * XXX
00307          * We'd like to test to see if the file is too big to mmap.  Since we
00308          * don't know what size or type off_t's or size_t's are, or the largest
00309          * unsigned integral type is, or what random insanity the local C
00310          * compiler will perpetrate, doing the comparison in a portable way is
00311          * flatly impossible.  Hope that mmap fails if the file is too large.
00312          */
00313 #define DB_MAXMMAPSIZE  (10 * 1024 * 1024)      /* 10 Mb. */
00314         if (F_ISSET(mfp, MP_CAN_MMAP)) {
00315                 if (!F_ISSET(dbmfp, MP_READONLY))
00316                         F_CLR(mfp, MP_CAN_MMAP);
00317                 if (path == NULL)
00318                         F_CLR(mfp, MP_CAN_MMAP);
00319                 if (finfop->ftype != 0)
00320                         F_CLR(mfp, MP_CAN_MMAP);
00321                 if (LF_ISSET(DB_NOMMAP) || F_ISSET(dbenv, DB_ENV_NOMMAP))
00322                         F_CLR(mfp, MP_CAN_MMAP);
00323                 maxmap = dbenv->mp_mmapsize == 0 ?
00324                     DB_MAXMMAPSIZE : dbenv->mp_mmapsize;
00325                 if (mbytes > maxmap / MEGABYTE ||
00326                     (mbytes == maxmap / MEGABYTE && bytes >= maxmap % MEGABYTE))
00327                         F_CLR(mfp, MP_CAN_MMAP);
00328         }
00329         dbmfp->addr = NULL;
00330         if (F_ISSET(mfp, MP_CAN_MMAP)) {
00331                 dbmfp->len = (size_t)mbytes * MEGABYTE + bytes;
00332                 if (CDB___os_mapfile(dbenv, rpath,
00333                     &dbmfp->fh, dbmfp->len, 1, &dbmfp->addr) != 0) {
00334                         dbmfp->addr = NULL;
00335                         F_CLR(mfp, MP_CAN_MMAP);
00336                 }
00337         }
00338         if (rpath != NULL)
00339                 CDB___os_freestr(rpath);
00340 
00341         MUTEX_THREAD_LOCK(dbmp->mutexp);
00342         TAILQ_INSERT_TAIL(&dbmp->dbmfq, dbmfp, q);
00343         MUTEX_THREAD_UNLOCK(dbmp->mutexp);
00344 
00345         *retp = dbmfp;
00346 
00347         return (0);
00348 
00349 err:    /*
00350          * Note that we do not have to free the thread mutex, because we
00351          * never get to here after we have successfully allocated it.
00352          */
00353         if (rpath != NULL)
00354                 CDB___os_freestr(rpath);
00355         if (F_ISSET(&dbmfp->fh, DB_FH_VALID))
00356                 (void)CDB___os_closehandle(&dbmfp->fh);
00357         if (dbmfp != NULL)
00358                 CDB___os_free(dbmfp, sizeof(DB_MPOOLFILE));
00359         return (ret);
00360 }
00361 static  MPOOL *mp;
00362 
00363 /*
00364  * __memp_mf_open --
00365  *      Open an MPOOLFILE.
00366  */
00367 static int
00368 __memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, flags, retp)
00369         DB_MPOOL *dbmp;
00370         const char *path;
00371         size_t pagesize;
00372         db_pgno_t last_pgno;
00373         DB_MPOOL_FINFO *finfop;
00374         u_int32_t flags;
00375         MPOOLFILE **retp;
00376 {
00377         MPOOLFILE *mfp;
00378         int ret;
00379         void *p;
00380 
00381 #define ISTEMPORARY     (path == NULL)
00382 
00383         /*
00384          * If not creating a temporary file, walk the list of MPOOLFILE's,
00385          * looking for a matching file.  Files backed by temporary files
00386          * or previously removed files can't match.
00387          *
00388          * DB_TRUNCATE support.
00389          *
00390          * The fileID is a filesystem unique number (e.g., a UNIX dev/inode
00391          * pair) plus a timestamp.  If files are removed and created in less
00392          * than a second, the fileID can be repeated.  The problem with
00393          * repetition happens when the file that previously had the fileID
00394          * value still has pages in the pool, since we don't want to use them
00395          * to satisfy requests for the new file.
00396          *
00397          * Because the DB_TRUNCATE flag reuses the dev/inode pair, repeated
00398          * opens with that flag set guarantees matching fileIDs when the
00399          * machine can open a file and then re-open with truncate within a
00400          * second.  For this reason, we pass that flag down, and, if we find
00401          * a matching entry, we ensure that it's never found again, and we
00402          * create a new entry for the current request.
00403          */
00404         if (!ISTEMPORARY) {
00405                 mp = dbmp->reginfo[0].primary;
00406                 for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
00407                     mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
00408                         if (F_ISSET(mfp, MP_DEADFILE | MP_TEMP))
00409                                 continue;
00410                         if (memcmp(finfop->fileid, R_ADDR(dbmp->reginfo,
00411                             mfp->fileid_off), DB_FILE_ID_LEN) == 0) {
00412                                 if (LF_ISSET(DB_TRUNCATE)) {
00413                                         MEMP_FREMOVE(mfp);
00414                                         continue;
00415                                 }
00416                                 if (finfop->clear_len != mfp->clear_len ||
00417                                     pagesize != mfp->stat.st_pagesize) {
00418                                         CDB___db_err(dbmp->dbenv,
00419                                     "%s: page size or clear length changed",
00420                                             path);
00421                                         return (EINVAL);
00422                                 }
00423 
00424                                 /*
00425                                  * It's possible that our needs for pre- and
00426                                  * post-processing are changing.  For example,
00427                                  * an application created a hash subdatabase
00428                                  * in a database that was previously all btree.
00429                                  */
00430                                 if (finfop->ftype != 0)
00431                                         mfp->ftype = finfop->ftype;
00432 
00433                                 ++mfp->ref_cnt;
00434 
00435                                 *retp = mfp;
00436                                 return (0);
00437                         }
00438                 }
00439         }
00440 
00441         /* Allocate a new MPOOLFILE. */
00442         if ((ret = CDB___memp_alloc(
00443             dbmp, dbmp->reginfo, NULL, sizeof(MPOOLFILE), NULL, &mfp)) != 0)
00444                 goto mem_err;
00445         *retp = mfp;
00446 
00447         /* Initialize the structure. */
00448         memset(mfp, 0, sizeof(MPOOLFILE));
00449         mfp->ref_cnt = 1;
00450         mfp->ftype = finfop->ftype;
00451         mfp->lsn_off = finfop->lsn_offset;
00452         mfp->clear_len = finfop->clear_len;
00453         mfp->cmpr_free = PGNO_INVALID;
00454 
00455         /*
00456          * If the user specifies DB_MPOOL_LAST or DB_MPOOL_NEW on a CDB_memp_fget,
00457          * we have to know the last page in the file.  Figure it out and save
00458          * it away.
00459          */
00460         mfp->stat.st_pagesize = pagesize;
00461         mfp->orig_last_pgno = mfp->last_pgno = last_pgno;
00462 
00463         if (ISTEMPORARY)
00464                 F_SET(mfp, MP_TEMP);
00465         else {
00466                 /* Copy the file path into shared memory. */
00467                 if ((ret = CDB___memp_alloc(dbmp, dbmp->reginfo,
00468                     NULL, strlen(path) + 1, &mfp->path_off, &p)) != 0)
00469                         goto err;
00470                 memcpy(p, path, strlen(path) + 1);
00471 
00472                 /* Copy the file identification string into shared memory. */
00473                 if ((ret = CDB___memp_alloc(dbmp, dbmp->reginfo,
00474                     NULL, DB_FILE_ID_LEN, &mfp->fileid_off, &p)) != 0)
00475                         goto err;
00476                 memcpy(p, finfop->fileid, DB_FILE_ID_LEN);
00477 
00478                 F_SET(mfp, MP_CAN_MMAP);
00479         }
00480 
00481         /* Copy the page cookie into shared memory. */
00482         if (finfop->pgcookie == NULL || finfop->pgcookie->size == 0) {
00483                 mfp->pgcookie_len = 0;
00484                 mfp->pgcookie_off = 0;
00485         } else {
00486                 if ((ret = CDB___memp_alloc(dbmp, dbmp->reginfo,
00487                     NULL, finfop->pgcookie->size, &mfp->pgcookie_off, &p)) != 0)
00488                         goto err;
00489                 memcpy(p, finfop->pgcookie->data, finfop->pgcookie->size);
00490                 mfp->pgcookie_len = finfop->pgcookie->size;
00491         }
00492 
00493         /* Prepend the MPOOLFILE to the list of MPOOLFILE's. */
00494         mp = dbmp->reginfo[0].primary;
00495         SH_TAILQ_INSERT_HEAD(&mp->mpfq, mfp, q, __mpoolfile);
00496 
00497         if((ret = CDB___memp_cmpr_open(dbmp->dbenv, mfp, path)) != 0)
00498           goto err;
00499         
00500         if (0) {
00501 err:            if (mfp->path_off != 0)
00502                         CDB___db_shalloc_free(dbmp->reginfo[0].addr,
00503                             R_ADDR(dbmp->reginfo, mfp->path_off));
00504                 if (mfp->fileid_off != 0)
00505                         CDB___db_shalloc_free(dbmp->reginfo[0].addr,
00506                             R_ADDR(dbmp->reginfo, mfp->fileid_off));
00507                 if (mfp != NULL)
00508                         CDB___db_shalloc_free(dbmp->reginfo[0].addr, mfp);
00509 mem_err:        CDB___db_err(dbmp->dbenv,
00510                     "Unable to allocate memory for mpool file");
00511         }
00512         return (ret);
00513 }
00514 
00515 /*
00516  * CDB_memp_fclose --
00517  *      Close a backing file for the memory pool.
00518  */
00519 int
00520 CDB_memp_fclose(dbmfp)
00521         DB_MPOOLFILE *dbmfp;
00522 {
00523         DB_ENV *dbenv;
00524         DB_MPOOL *dbmp;
00525         MPOOLFILE *mfp;
00526         int ret, t_ret;
00527 
00528         dbmp = dbmfp->dbmp;
00529         dbenv = dbmp->dbenv;
00530         ret = 0;
00531 
00532         PANIC_CHECK(dbenv);
00533 
00534 #ifdef HAVE_RPC
00535         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00536                 return (__dbcl_memp_fclose(dbmfp));
00537 #endif
00538 
00539         /*
00540          * Remove the DB_MPOOLFILE from the queue.  This has to happen before
00541          * we perform any action that can fail, otherwise CDB___memp_close may
00542          * loop infinitely when calling us to discard all of the DB_MPOOLFILEs.
00543          */
00544         for (;;) {
00545                 MUTEX_THREAD_LOCK(dbmp->mutexp);
00546 
00547                 /*
00548                  * We have to reference count DB_MPOOLFILE structures as other
00549                  * threads may be using them.  The problem only happens if the
00550                  * application makes a bad design choice.  Here's the path:
00551                  *
00552                  * Thread A opens a database.
00553                  * Thread B uses thread A's DB_MPOOLFILE to write a buffer
00554                  *    in order to free up memory in the mpool cache.
00555                  * Thread A closes the database while thread B is using the
00556                  *    DB_MPOOLFILE structure.
00557                  *
00558                  * By opening all databases before creating the threads, and
00559                  * closing them after the threads have exited, applications
00560                  * get better performance and avoid the problem path entirely.
00561                  *
00562                  * Regardless, holding the DB_MPOOLFILE to flush a dirty buffer
00563                  * is a short-term lock, even in worst case, since we better be
00564                  * the only thread of control using the DB_MPOOLFILE structure
00565                  * to read pages *into* the cache.  Wait until we're the only
00566                  * reference holder and remove the DB_MPOOLFILE structure from
00567                  * the list, so nobody else can even find it.
00568                  */
00569                 if (dbmfp->ref == 1) {
00570                         TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q);
00571                         break;
00572                 }
00573                 MUTEX_THREAD_UNLOCK(dbmp->mutexp);
00574 
00575                 (void)CDB___os_sleep(dbenv, 1, 0);
00576         }
00577         MUTEX_THREAD_UNLOCK(dbmp->mutexp);
00578 
00579         /* Complain if pinned blocks never returned. */
00580         if (dbmfp->pinref != 0)
00581                 CDB___db_err(dbenv, "%s: close: %lu blocks left pinned",
00582                     CDB___memp_fn(dbmfp), (u_long)dbmfp->pinref);
00583 
00584         /* Discard any mmap information. */
00585         if (dbmfp->addr != NULL &&
00586             (ret = CDB___os_unmapfile(dbenv, dbmfp->addr, dbmfp->len)) != 0)
00587                 CDB___db_err(dbenv, "%s: %s", CDB___memp_fn(dbmfp), CDB_db_strerror(ret));
00588 
00589         /* Close the file; temporary files may not yet have been created. */
00590         if (F_ISSET(&dbmfp->fh, DB_FH_VALID) &&
00591             (t_ret = CDB___os_closehandle(&dbmfp->fh)) != 0) {
00592                 CDB___db_err(dbenv, "%s: %s", CDB___memp_fn(dbmfp), CDB_db_strerror(t_ret));
00593                 if (ret != 0)
00594                         t_ret = ret;
00595         }
00596 
00597         /* Discard the thread mutex. */
00598         if (dbmfp->mutexp != NULL)
00599                 CDB___db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp);
00600 
00601         /*
00602          * Discard our reference on the the underlying MPOOLFILE, and close
00603          * it if it's no longer useful to anyone.
00604          *
00605          * If we're not discarding it, and it's a temp file, this means
00606          * all the outstanding references belong to unflushed buffers.
00607          * (A temp file can only be referenced by one DB_MPOOLFILE).
00608          * We don't care about preserving any of those buffers, so mark
00609          * the MPOOLFILE as dead so that when we try to flush them,
00610          * even the dirty ones just get discarded.
00611          */
00612         R_LOCK(dbenv, dbmp->reginfo);
00613         mfp = dbmfp->mfp;
00614         if (--mfp->ref_cnt == 0)
00615                 CDB___memp_mf_discard(dbmp, mfp);
00616         else if (F_ISSET(mfp, MP_TEMP))
00617                 MEMP_FREMOVE(mfp);
00618         R_UNLOCK(dbenv, dbmp->reginfo);
00619 
00620         /* Discard the DB_MPOOLFILE structure. */
00621         CDB___os_free(dbmfp, sizeof(DB_MPOOLFILE));
00622 
00623         return (ret);
00624 }
00625 
00626 /*
00627  * CDB___memp_mf_discard --
00628  *      Discard an MPOOLFILE.
00629  *
00630  * PUBLIC: void CDB___memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *));
00631  */
00632 void
00633 CDB___memp_mf_discard(dbmp, mfp)
00634         DB_MPOOL *dbmp;
00635         MPOOLFILE *mfp;
00636 {
00637         MPOOL *mp;
00638 
00639         mp = dbmp->reginfo[0].primary;
00640 
00641         /* Delete from the list of MPOOLFILEs. */
00642         SH_TAILQ_REMOVE(&mp->mpfq, mfp, q, __mpoolfile);
00643 
00644         /* Free the space. */
00645         if (mfp->path_off != 0)
00646                 CDB___db_shalloc_free(dbmp->reginfo[0].addr,
00647                     R_ADDR(dbmp->reginfo, mfp->path_off));
00648         if (mfp->fileid_off != 0)
00649                 CDB___db_shalloc_free(dbmp->reginfo[0].addr,
00650                     R_ADDR(dbmp->reginfo, mfp->fileid_off));
00651         if (mfp->pgcookie_off != 0)
00652                 CDB___db_shalloc_free(dbmp->reginfo[0].addr,
00653                     R_ADDR(dbmp->reginfo, mfp->pgcookie_off));
00654         CDB___db_shalloc_free(dbmp->reginfo[0].addr, mfp);
00655 }
00656 
00657 /*
00658  * CDB___memp_fremove --
00659  *      Remove an underlying file from the system.
00660  *
00661  * PUBLIC: int CDB___memp_fremove __P((DB_MPOOLFILE *));
00662  */
00663 int
00664 CDB___memp_fremove(dbmfp)
00665         DB_MPOOLFILE *dbmfp;
00666 {
00667         DB_ENV *dbenv;
00668         DB_MPOOL *dbmp;
00669         MPOOLFILE *mfp;
00670 
00671         dbmp = dbmfp->dbmp;
00672         dbenv = dbmp->dbenv;
00673         mfp = dbmfp->mfp;
00674 
00675         PANIC_CHECK(dbenv);
00676 
00677         R_LOCK(dbenv, dbmp->reginfo);
00678 
00679         MEMP_FREMOVE(mfp);
00680 
00681         R_UNLOCK(dbenv, dbmp->reginfo);
00682 
00683         return (0);
00684 }
00685 
00686 /*
00687  * CDB___memp_fn --
00688  *      On errors we print whatever is available as the file name.
00689  *
00690  * PUBLIC: char * CDB___memp_fn __P((DB_MPOOLFILE *));
00691  */
00692 char *
00693 CDB___memp_fn(dbmfp)
00694         DB_MPOOLFILE *dbmfp;
00695 {
00696         return (CDB___memp_fns(dbmfp->dbmp, dbmfp->mfp));
00697 }
00698 
00699 /*
00700  * CDB___memp_fns --
00701  *      On errors we print whatever is available as the file name.
00702  *
00703  * PUBLIC: char * CDB___memp_fns __P((DB_MPOOL *, MPOOLFILE *));
00704  *
00705  */
00706 char *
00707 CDB___memp_fns(dbmp, mfp)
00708         DB_MPOOL *dbmp;
00709         MPOOLFILE *mfp;
00710 {
00711         if (mfp->path_off == 0)
00712                 return ((char *)"temporary");
00713 
00714         return ((char *)R_ADDR(dbmp->reginfo, mfp->path_off));
00715 }

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