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 }