mp_fopen.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:20k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: mp_fopen.c,v 11.41 2001/01/10 04:50:53 ubell Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #ifdef  HAVE_RPC
  16. #include "db_server.h"
  17. #endif
  18. #include "db_int.h"
  19. #include "db_shash.h"
  20. #include "mp.h"
  21. #ifdef HAVE_RPC
  22. #include "gen_client_ext.h"
  23. #include "rpc_client_ext.h"
  24. #endif
  25. static int __memp_mf_open __P((DB_MPOOL *, const char *,
  26.     size_t, db_pgno_t, DB_MPOOL_FINFO *, u_int32_t, MPOOLFILE **));
  27. /*
  28.  * MEMP_FREMOVE --
  29.  * Discard an MPOOLFILE and any buffers it references: update the flags
  30.  * so we never try to write buffers associated with the file, nor can we
  31.  * find it when looking for files to join.  In addition, clear the ftype
  32.  * field, there's no reason to post-process pages, they can be discarded
  33.  * by any thread.
  34.  */
  35. #define MEMP_FREMOVE(mfp) {
  36. mfp->ftype = 0;
  37. F_SET(mfp, MP_DEADFILE);
  38. }
  39. /*
  40.  * memp_fopen --
  41.  * Open a backing file for the memory pool.
  42.  */
  43. int
  44. memp_fopen(dbenv, path, flags, mode, pagesize, finfop, retp)
  45. DB_ENV *dbenv;
  46. const char *path;
  47. u_int32_t flags;
  48. int mode;
  49. size_t pagesize;
  50. DB_MPOOL_FINFO *finfop;
  51. DB_MPOOLFILE **retp;
  52. {
  53. DB_MPOOL *dbmp;
  54. int ret;
  55. #ifdef HAVE_RPC
  56. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  57. return (__dbcl_memp_fopen(dbenv, path, flags,
  58.     mode, pagesize, finfop, retp));
  59. #endif
  60. PANIC_CHECK(dbenv);
  61. ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL);
  62. dbmp = dbenv->mp_handle;
  63. /* Validate arguments. */
  64. if ((ret = __db_fchk(dbenv, "memp_fopen", flags,
  65.     DB_CREATE |
  66.     DB_NOMMAP | DB_ODDFILESIZE | DB_RDONLY | DB_TRUNCATE)) != 0)
  67. return (ret);
  68. /* Require a non-zero pagesize. */
  69. if (pagesize == 0 ||
  70.     (finfop != NULL && finfop->clear_len > pagesize)) {
  71. __db_err(dbenv, "memp_fopen: illegal page size.");
  72. return (EINVAL);
  73. }
  74. return (__memp_fopen(dbmp,
  75.     NULL, path, flags, mode, pagesize, 1, finfop, retp));
  76. }
  77. /*
  78.  * __memp_set_unlink -- set unlink on last close flag.
  79.  *
  80.  * PUBLIC: void __memp_set_unlink __P((DB_MPOOLFILE *));
  81.  */
  82. void
  83. __memp_set_unlink(dbmpf)
  84. DB_MPOOLFILE *dbmpf;
  85. {
  86. DB_MPOOL *dbmp;
  87. dbmp = dbmpf->dbmp;
  88. R_LOCK(dbmp->dbenv, dbmp->reginfo);
  89. F_SET(dbmpf->mfp, MP_UNLINK);
  90. R_UNLOCK(dbmp->dbenv, dbmp->reginfo);
  91. }
  92. /*
  93.  * __memp_clear_unlink -- clear unlink on last close flag.
  94.  *
  95.  * PUBLIC: void __memp_clear_unlink __P((DB_MPOOLFILE *));
  96.  */
  97. void
  98. __memp_clear_unlink(dbmpf)
  99. DB_MPOOLFILE *dbmpf;
  100. {
  101. DB_MPOOL *dbmp;
  102. dbmp = dbmpf->dbmp;
  103. /*
  104.  * This bit is protected in the queue code because the metapage
  105.  * is locked so we can avoid geting the region lock.
  106.  * If this gets used from other than the queue code, we cannot.
  107.  */
  108. if (!F_ISSET(dbmpf->mfp, MP_UNLINK))
  109. return;
  110. R_LOCK(dbmp->dbenv, dbmp->reginfo);
  111. F_CLR(dbmpf->mfp, MP_UNLINK);
  112. R_UNLOCK(dbmp->dbenv, dbmp->reginfo);
  113. }
  114. /*
  115.  * __memp_fopen --
  116.  * Open a backing file for the memory pool; internal version.
  117.  *
  118.  * PUBLIC: int __memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *,
  119.  * PUBLIC:    u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
  120.  */
  121. int
  122. __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
  123. DB_MPOOL *dbmp;
  124. MPOOLFILE *mfp;
  125. const char *path;
  126. u_int32_t flags;
  127. int mode, needlock;
  128. size_t pagesize;
  129. DB_MPOOL_FINFO *finfop;
  130. DB_MPOOLFILE **retp;
  131. {
  132. DB_ENV *dbenv;
  133. DB_MPOOLFILE *dbmfp;
  134. DB_MPOOL_FINFO finfo;
  135. db_pgno_t last_pgno;
  136. size_t maxmap;
  137. u_int32_t mbytes, bytes, oflags;
  138. int ret;
  139. u_int8_t idbuf[DB_FILE_ID_LEN];
  140. char *rpath;
  141. dbenv = dbmp->dbenv;
  142. ret = 0;
  143. rpath = NULL;
  144. /*
  145.  * If mfp is provided, we take the DB_MPOOL_FINFO information from
  146.  * the mfp.  We don't bother initializing everything, because some
  147.  * of them are expensive to acquire.  If no mfp is provided and the
  148.  * finfop argument is NULL, we default the values.
  149.  */
  150. if (finfop == NULL) {
  151. memset(&finfo, 0, sizeof(finfo));
  152. if (mfp != NULL) {
  153. finfo.ftype = mfp->ftype;
  154. finfo.pgcookie = NULL;
  155. finfo.fileid = NULL;
  156. finfo.lsn_offset = mfp->lsn_off;
  157. finfo.clear_len = mfp->clear_len;
  158. } else {
  159. finfo.ftype = 0;
  160. finfo.pgcookie = NULL;
  161. finfo.fileid = NULL;
  162. finfo.lsn_offset = -1;
  163. finfo.clear_len = 0;
  164. }
  165. finfop = &finfo;
  166. }
  167. /* Allocate and initialize the per-process structure. */
  168. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0)
  169. return (ret);
  170. dbmfp->dbmp = dbmp;
  171. dbmfp->ref = 1;
  172. if (LF_ISSET(DB_RDONLY))
  173. F_SET(dbmfp, MP_READONLY);
  174. if (path == NULL) {
  175. if (LF_ISSET(DB_RDONLY)) {
  176. __db_err(dbenv,
  177.     "memp_fopen: temporary files can't be readonly");
  178. ret = EINVAL;
  179. goto err;
  180. }
  181. last_pgno = 0;
  182. } else {
  183. /* Get the real name for this file and open it. */
  184. if ((ret = __db_appname(dbenv,
  185.     DB_APP_DATA, NULL, path, 0, NULL, &rpath)) != 0)
  186. goto err;
  187. oflags = 0;
  188. if (LF_ISSET(DB_CREATE))
  189. oflags |= DB_OSO_CREATE;
  190. if (LF_ISSET(DB_RDONLY))
  191. oflags |= DB_OSO_RDONLY;
  192. if ((ret =
  193.    __os_open(dbenv, rpath, oflags, mode, &dbmfp->fh)) != 0) {
  194. if (!LF_ISSET(DB_EXTENT))
  195. __db_err(dbenv,
  196.     "%s: %s", rpath, db_strerror(ret));
  197. goto err;
  198. }
  199. /*
  200.  * Don't permit files that aren't a multiple of the pagesize,
  201.  * and find the number of the last page in the file, all the
  202.  * time being careful not to overflow 32 bits.
  203.  *
  204.  * !!!
  205.  * We can't use off_t's here, or in any code in the mainline
  206.  * library for that matter.  (We have to use them in the os
  207.  * stubs, of course, as there are system calls that take them
  208.  * as arguments.)  The reason is that some customers build in
  209.  * environments where an off_t is 32-bits, but still run where
  210.  * offsets are 64-bits, and they pay us a lot of money.
  211.  */
  212. if ((ret = __os_ioinfo(dbenv, rpath,
  213.     &dbmfp->fh, &mbytes, &bytes, NULL)) != 0) {
  214. __db_err(dbenv, "%s: %s", rpath, db_strerror(ret));
  215. goto err;
  216. }
  217. /*
  218.  * If we're doing a verify, we might have to cope with
  219.  * a truncated file;  if the file size is not a multiple
  220.  * of the page size, round down to a page--we'll
  221.  * take care of the partial page outside the memp system.
  222.  */
  223. /* Page sizes have to be a power-of-two, ignore mbytes. */
  224. if (bytes % pagesize != 0) {
  225. if (LF_ISSET(DB_ODDFILESIZE))
  226. /*
  227.  * If we're doing a verify, we might
  228.  * have to cope with a truncated file;
  229.  * round down, we'll worry about the partial
  230.  * page outside the memp system.
  231.  */
  232. bytes -= (bytes % pagesize);
  233. else {
  234. __db_err(dbenv,
  235. "%s: file size not a multiple of the pagesize",
  236.     rpath);
  237. ret = EINVAL;
  238. goto err;
  239. }
  240. }
  241. last_pgno = mbytes * (MEGABYTE / pagesize);
  242. last_pgno += bytes / pagesize;
  243. /* Correction: page numbers are zero-based, not 1-based. */
  244. if (last_pgno != 0)
  245. --last_pgno;
  246. /*
  247.  * Get the file id if we weren't given one.  Generated file id's
  248.  * don't use timestamps, otherwise there'd be no chance of any
  249.  * other process joining the party.
  250.  */
  251. if (finfop->fileid == NULL) {
  252. if ((ret = __os_fileid(dbenv, rpath, 0, idbuf)) != 0)
  253. goto err;
  254. finfop->fileid = idbuf;
  255. }
  256. }
  257. /*
  258.  * If we weren't provided an underlying shared object to join with,
  259.  * find/allocate the shared file objects.  Also allocate space for
  260.  * for the per-process thread lock.
  261.  */
  262. if (needlock)
  263. R_LOCK(dbenv, dbmp->reginfo);
  264. if (mfp == NULL)
  265. ret = __memp_mf_open(
  266.     dbmp, path, pagesize, last_pgno, finfop, flags, &mfp);
  267. else {
  268. ++mfp->mpf_cnt;
  269. ret = 0;
  270. }
  271. if (needlock)
  272. R_UNLOCK(dbenv, dbmp->reginfo);
  273. if (ret != 0)
  274. goto err;
  275. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  276. if ((ret = __db_mutex_alloc(
  277.     dbenv, dbmp->reginfo, &dbmfp->mutexp)) != 0)
  278. goto err;
  279. if ((ret = __db_mutex_init(
  280.     dbenv, dbmfp->mutexp, 0, MUTEX_THREAD)) != 0)
  281. goto err;
  282. /* XXX: KEITH: CLOSE THE FILE ON FAILURE? */
  283. }
  284. dbmfp->mfp = mfp;
  285. /*
  286.  * If a file:
  287.  * + is read-only
  288.  * + isn't temporary
  289.  * + doesn't require any pgin/pgout support
  290.  * + the DB_NOMMAP flag wasn't set (in either the file open or
  291.  *   the environment in which it was opened)
  292.  * + and is less than mp_mmapsize bytes in size
  293.  *
  294.  * we can mmap it instead of reading/writing buffers.  Don't do error
  295.  * checking based on the mmap call failure.  We want to do normal I/O
  296.  * on the file if the reason we failed was because the file was on an
  297.  * NFS mounted partition, and we can fail in buffer I/O just as easily
  298.  * as here.
  299.  *
  300.  * XXX
  301.  * We'd like to test to see if the file is too big to mmap.  Since we
  302.  * don't know what size or type off_t's or size_t's are, or the largest
  303.  * unsigned integral type is, or what random insanity the local C
  304.  * compiler will perpetrate, doing the comparison in a portable way is
  305.  * flatly impossible.  Hope that mmap fails if the file is too large.
  306.  */
  307. #define DB_MAXMMAPSIZE (10 * 1024 * 1024) /* 10 Mb. */
  308. if (F_ISSET(mfp, MP_CAN_MMAP)) {
  309. if (!F_ISSET(dbmfp, MP_READONLY))
  310. F_CLR(mfp, MP_CAN_MMAP);
  311. if (path == NULL)
  312. F_CLR(mfp, MP_CAN_MMAP);
  313. if (finfop->ftype != 0)
  314. F_CLR(mfp, MP_CAN_MMAP);
  315. if (LF_ISSET(DB_NOMMAP) || F_ISSET(dbenv, DB_ENV_NOMMAP))
  316. F_CLR(mfp, MP_CAN_MMAP);
  317. maxmap = dbenv->mp_mmapsize == 0 ?
  318.     DB_MAXMMAPSIZE : dbenv->mp_mmapsize;
  319. if (mbytes > maxmap / MEGABYTE ||
  320.     (mbytes == maxmap / MEGABYTE && bytes >= maxmap % MEGABYTE))
  321. F_CLR(mfp, MP_CAN_MMAP);
  322. }
  323. dbmfp->addr = NULL;
  324. if (F_ISSET(mfp, MP_CAN_MMAP)) {
  325. dbmfp->len = (size_t)mbytes * MEGABYTE + bytes;
  326. if (__os_mapfile(dbenv, rpath,
  327.     &dbmfp->fh, dbmfp->len, 1, &dbmfp->addr) != 0) {
  328. dbmfp->addr = NULL;
  329. F_CLR(mfp, MP_CAN_MMAP);
  330. }
  331. }
  332. if (rpath != NULL)
  333. __os_freestr(rpath);
  334. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  335. TAILQ_INSERT_TAIL(&dbmp->dbmfq, dbmfp, q);
  336. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  337. *retp = dbmfp;
  338. return (0);
  339. err: /*
  340.  * Note that we do not have to free the thread mutex, because we
  341.  * never get to here after we have successfully allocated it.
  342.  */
  343. if (rpath != NULL)
  344. __os_freestr(rpath);
  345. if (F_ISSET(&dbmfp->fh, DB_FH_VALID))
  346. (void)__os_closehandle(&dbmfp->fh);
  347. if (dbmfp != NULL) {
  348. if (dbmfp->mutexp != NULL)
  349. __db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp);
  350. __os_free(dbmfp, sizeof(DB_MPOOLFILE));
  351. }
  352. return (ret);
  353. }
  354. /*
  355.  * __memp_mf_open --
  356.  * Open an MPOOLFILE.
  357.  */
  358. static int
  359. __memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, flags, retp)
  360. DB_MPOOL *dbmp;
  361. const char *path;
  362. size_t pagesize;
  363. db_pgno_t last_pgno;
  364. DB_MPOOL_FINFO *finfop;
  365. u_int32_t flags;
  366. MPOOLFILE **retp;
  367. {
  368. MPOOL *mp;
  369. MPOOLFILE *mfp;
  370. int ret;
  371. void *p;
  372. #define ISTEMPORARY (path == NULL)
  373. /*
  374.  * If not creating a temporary file, walk the list of MPOOLFILE's,
  375.  * looking for a matching file.  Files backed by temporary files
  376.  * or previously removed files can't match.
  377.  *
  378.  * DB_TRUNCATE support.
  379.  *
  380.  * The fileID is a filesystem unique number (e.g., a UNIX dev/inode
  381.  * pair) plus a timestamp.  If files are removed and created in less
  382.  * than a second, the fileID can be repeated.  The problem with
  383.  * repetition happens when the file that previously had the fileID
  384.  * value still has pages in the pool, since we don't want to use them
  385.  * to satisfy requests for the new file.
  386.  *
  387.  * Because the DB_TRUNCATE flag reuses the dev/inode pair, repeated
  388.  * opens with that flag set guarantees matching fileIDs when the
  389.  * machine can open a file and then re-open with truncate within a
  390.  * second.  For this reason, we pass that flag down, and, if we find
  391.  * a matching entry, we ensure that it's never found again, and we
  392.  * create a new entry for the current request.
  393.  */
  394. if (!ISTEMPORARY) {
  395. mp = dbmp->reginfo[0].primary;
  396. for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
  397.     mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
  398. if (F_ISSET(mfp, MP_DEADFILE | MP_TEMP))
  399. continue;
  400. if (memcmp(finfop->fileid, R_ADDR(dbmp->reginfo,
  401.     mfp->fileid_off), DB_FILE_ID_LEN) == 0) {
  402. if (LF_ISSET(DB_TRUNCATE)) {
  403. MEMP_FREMOVE(mfp);
  404. continue;
  405. }
  406. if (finfop->clear_len != mfp->clear_len ||
  407.     pagesize != mfp->stat.st_pagesize) {
  408. __db_err(dbmp->dbenv,
  409.     "%s: page size or clear length changed",
  410.     path);
  411. return (EINVAL);
  412. }
  413. /*
  414.  * It's possible that our needs for pre- and
  415.  * post-processing are changing.  For example,
  416.  * an application created a hash subdatabase
  417.  * in a database that was previously all btree.
  418.  */
  419. if (finfop->ftype != 0)
  420. mfp->ftype = finfop->ftype;
  421. ++mfp->mpf_cnt;
  422. *retp = mfp;
  423. return (0);
  424. }
  425. }
  426. }
  427. /* Allocate a new MPOOLFILE. */
  428. if ((ret = __memp_alloc(
  429.     dbmp, dbmp->reginfo, NULL, sizeof(MPOOLFILE), NULL, &mfp)) != 0)
  430. goto mem_err;
  431. *retp = mfp;
  432. /* Initialize the structure. */
  433. memset(mfp, 0, sizeof(MPOOLFILE));
  434. mfp->mpf_cnt = 1;
  435. mfp->ftype = finfop->ftype;
  436. mfp->lsn_off = finfop->lsn_offset;
  437. mfp->clear_len = finfop->clear_len;
  438. /*
  439.  * If the user specifies DB_MPOOL_LAST or DB_MPOOL_NEW on a memp_fget,
  440.  * we have to know the last page in the file.  Figure it out and save
  441.  * it away.
  442.  */
  443. mfp->stat.st_pagesize = pagesize;
  444. mfp->orig_last_pgno = mfp->last_pgno = last_pgno;
  445. if (ISTEMPORARY)
  446. F_SET(mfp, MP_TEMP);
  447. else {
  448. /* Copy the file path into shared memory. */
  449. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  450.     NULL, strlen(path) + 1, &mfp->path_off, &p)) != 0)
  451. goto err;
  452. memcpy(p, path, strlen(path) + 1);
  453. /* Copy the file identification string into shared memory. */
  454. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  455.     NULL, DB_FILE_ID_LEN, &mfp->fileid_off, &p)) != 0)
  456. goto err;
  457. memcpy(p, finfop->fileid, DB_FILE_ID_LEN);
  458. F_SET(mfp, MP_CAN_MMAP);
  459. }
  460. /* Copy the page cookie into shared memory. */
  461. if (finfop->pgcookie == NULL || finfop->pgcookie->size == 0) {
  462. mfp->pgcookie_len = 0;
  463. mfp->pgcookie_off = 0;
  464. } else {
  465. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  466.     NULL, finfop->pgcookie->size, &mfp->pgcookie_off, &p)) != 0)
  467. goto err;
  468. memcpy(p, finfop->pgcookie->data, finfop->pgcookie->size);
  469. mfp->pgcookie_len = finfop->pgcookie->size;
  470. }
  471. /* Prepend the MPOOLFILE to the list of MPOOLFILE's. */
  472. mp = dbmp->reginfo[0].primary;
  473. SH_TAILQ_INSERT_HEAD(&mp->mpfq, mfp, q, __mpoolfile);
  474. if (0) {
  475. err: if (mfp->path_off != 0)
  476. __db_shalloc_free(dbmp->reginfo[0].addr,
  477.     R_ADDR(dbmp->reginfo, mfp->path_off));
  478. if (mfp->fileid_off != 0)
  479. __db_shalloc_free(dbmp->reginfo[0].addr,
  480.     R_ADDR(dbmp->reginfo, mfp->fileid_off));
  481. if (mfp != NULL)
  482. __db_shalloc_free(dbmp->reginfo[0].addr, mfp);
  483. mem_err: __db_err(dbmp->dbenv,
  484.     "Unable to allocate memory for mpool file");
  485. }
  486. return (ret);
  487. }
  488. /*
  489.  * memp_fclose --
  490.  * Close a backing file for the memory pool.
  491.  */
  492. int
  493. memp_fclose(dbmfp)
  494. DB_MPOOLFILE *dbmfp;
  495. {
  496. DB_ENV *dbenv;
  497. DB_MPOOL *dbmp;
  498. MPOOLFILE *mfp;
  499. char *rpath;
  500. int ret, t_ret;
  501. dbmp = dbmfp->dbmp;
  502. dbenv = dbmp->dbenv;
  503. ret = 0;
  504. PANIC_CHECK(dbenv);
  505. #ifdef HAVE_RPC
  506. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  507. return (__dbcl_memp_fclose(dbmfp));
  508. #endif
  509. /*
  510.  * Remove the DB_MPOOLFILE from the queue.  This has to happen before
  511.  * we perform any action that can fail, otherwise __memp_close may
  512.  * loop infinitely when calling us to discard all of the DB_MPOOLFILEs.
  513.  */
  514. for (;;) {
  515. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  516. /*
  517.  * We have to reference count DB_MPOOLFILE structures as other
  518.  * threads may be using them.  The problem only happens if the
  519.  * application makes a bad design choice.  Here's the path:
  520.  *
  521.  * Thread A opens a database.
  522.  * Thread B uses thread A's DB_MPOOLFILE to write a buffer
  523.  *    in order to free up memory in the mpool cache.
  524.  * Thread A closes the database while thread B is using the
  525.  *    DB_MPOOLFILE structure.
  526.  *
  527.  * By opening all databases before creating the threads, and
  528.  * closing them after the threads have exited, applications
  529.  * get better performance and avoid the problem path entirely.
  530.  *
  531.  * Regardless, holding the DB_MPOOLFILE to flush a dirty buffer
  532.  * is a short-term lock, even in worst case, since we better be
  533.  * the only thread of control using the DB_MPOOLFILE structure
  534.  * to read pages *into* the cache.  Wait until we're the only
  535.  * reference holder and remove the DB_MPOOLFILE structure from
  536.  * the list, so nobody else can even find it.
  537.  */
  538. if (dbmfp->ref == 1) {
  539. TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q);
  540. break;
  541. }
  542. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  543. (void)__os_sleep(dbenv, 1, 0);
  544. }
  545. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  546. /* Complain if pinned blocks never returned. */
  547. if (dbmfp->pinref != 0)
  548. __db_err(dbenv, "%s: close: %lu blocks left pinned",
  549.     __memp_fn(dbmfp), (u_long)dbmfp->pinref);
  550. /* Discard any mmap information. */
  551. if (dbmfp->addr != NULL &&
  552.     (ret = __os_unmapfile(dbenv, dbmfp->addr, dbmfp->len)) != 0)
  553. __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(ret));
  554. /* Close the file; temporary files may not yet have been created. */
  555. if (F_ISSET(&dbmfp->fh, DB_FH_VALID) &&
  556.     (t_ret = __os_closehandle(&dbmfp->fh)) != 0) {
  557. __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(t_ret));
  558. if (ret != 0)
  559. t_ret = ret;
  560. }
  561. /* Discard the thread mutex. */
  562. if (dbmfp->mutexp != NULL)
  563. __db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp);
  564. /*
  565.  * Discard our reference on the the underlying MPOOLFILE, and close
  566.  * it if it's no longer useful to anyone.
  567.  *
  568.  * If we're not discarding it, and it's a temp file, this means
  569.  * all the outstanding references belong to unflushed buffers.
  570.  * (A temp file can only be referenced by one DB_MPOOLFILE).
  571.  * We don't care about preserving any of those buffers, so mark
  572.  * the MPOOLFILE as dead so that when we try to flush them,
  573.  * even the dirty ones just get discarded.
  574.  */
  575. R_LOCK(dbenv, dbmp->reginfo);
  576. mfp = dbmfp->mfp;
  577. if (--mfp->mpf_cnt == 0) {
  578. if (F_ISSET(mfp, MP_UNLINK)) {
  579. MEMP_FREMOVE(mfp);
  580. if ((t_ret = __db_appname(dbmp->dbenv,
  581.     DB_APP_DATA, NULL, R_ADDR(dbmp->reginfo,
  582.     mfp->path_off), 0, NULL, &rpath)) != 0 && ret == 0)
  583. ret = t_ret;
  584. if (t_ret == 0 && (t_ret =
  585.     __os_unlink(dbmp->dbenv, rpath) != 0 && ret == 0))
  586. ret = t_ret;
  587. __os_free(rpath, 0);
  588. }
  589. if (mfp->block_cnt == 0)
  590. __memp_mf_discard(dbmp, mfp);
  591. }
  592. else if (F_ISSET(mfp, MP_TEMP))
  593. MEMP_FREMOVE(mfp);
  594. R_UNLOCK(dbenv, dbmp->reginfo);
  595. /* Discard the DB_MPOOLFILE structure. */
  596. __os_free(dbmfp, sizeof(DB_MPOOLFILE));
  597. return (ret);
  598. }
  599. /*
  600.  * __memp_mf_discard --
  601.  * Discard an MPOOLFILE.
  602.  *
  603.  * PUBLIC: void __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *));
  604.  */
  605. void
  606. __memp_mf_discard(dbmp, mfp)
  607. DB_MPOOL *dbmp;
  608. MPOOLFILE *mfp;
  609. {
  610. MPOOL *mp;
  611. mp = dbmp->reginfo[0].primary;
  612. /* Delete from the list of MPOOLFILEs. */
  613. SH_TAILQ_REMOVE(&mp->mpfq, mfp, q, __mpoolfile);
  614. /* Free the space. */
  615. if (mfp->path_off != 0)
  616. __db_shalloc_free(dbmp->reginfo[0].addr,
  617.     R_ADDR(dbmp->reginfo, mfp->path_off));
  618. if (mfp->fileid_off != 0)
  619. __db_shalloc_free(dbmp->reginfo[0].addr,
  620.     R_ADDR(dbmp->reginfo, mfp->fileid_off));
  621. if (mfp->pgcookie_off != 0)
  622. __db_shalloc_free(dbmp->reginfo[0].addr,
  623.     R_ADDR(dbmp->reginfo, mfp->pgcookie_off));
  624. __db_shalloc_free(dbmp->reginfo[0].addr, mfp);
  625. }
  626. /*
  627.  * __memp_fremove --
  628.  * Remove an underlying file from the system.
  629.  *
  630.  * PUBLIC: int __memp_fremove __P((DB_MPOOLFILE *));
  631.  */
  632. int
  633. __memp_fremove(dbmfp)
  634. DB_MPOOLFILE *dbmfp;
  635. {
  636. DB_ENV *dbenv;
  637. DB_MPOOL *dbmp;
  638. MPOOLFILE *mfp;
  639. dbmp = dbmfp->dbmp;
  640. dbenv = dbmp->dbenv;
  641. mfp = dbmfp->mfp;
  642. PANIC_CHECK(dbenv);
  643. R_LOCK(dbenv, dbmp->reginfo);
  644. MEMP_FREMOVE(mfp);
  645. R_UNLOCK(dbenv, dbmp->reginfo);
  646. return (0);
  647. }
  648. /*
  649.  * __memp_fn --
  650.  * On errors we print whatever is available as the file name.
  651.  *
  652.  * PUBLIC: char * __memp_fn __P((DB_MPOOLFILE *));
  653.  */
  654. char *
  655. __memp_fn(dbmfp)
  656. DB_MPOOLFILE *dbmfp;
  657. {
  658. return (__memp_fns(dbmfp->dbmp, dbmfp->mfp));
  659. }
  660. /*
  661.  * __memp_fns --
  662.  * On errors we print whatever is available as the file name.
  663.  *
  664.  * PUBLIC: char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *));
  665.  *
  666.  */
  667. char *
  668. __memp_fns(dbmp, mfp)
  669. DB_MPOOL *dbmp;
  670. MPOOLFILE *mfp;
  671. {
  672. if (mfp->path_off == 0)
  673. return ((char *)"temporary");
  674. return ((char *)R_ADDR(dbmp->reginfo, mfp->path_off));
  675. }