mp_fopen.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:26k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  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.90 2002/08/26 15:22:01 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "dbinc/db_shash.h"
  17. #include "dbinc/mp.h"
  18. static int  __memp_fclose __P((DB_MPOOLFILE *, u_int32_t));
  19. static int  __memp_fopen __P((DB_MPOOLFILE *,
  20. const char *, u_int32_t, int, size_t));
  21. static void __memp_get_fileid __P((DB_MPOOLFILE *, u_int8_t *));
  22. static void __memp_last_pgno __P((DB_MPOOLFILE *, db_pgno_t *));
  23. static void __memp_refcnt __P((DB_MPOOLFILE *, db_pgno_t *));
  24. static int  __memp_set_clear_len __P((DB_MPOOLFILE *, u_int32_t));
  25. static int  __memp_set_fileid __P((DB_MPOOLFILE *, u_int8_t *));
  26. static int  __memp_set_ftype __P((DB_MPOOLFILE *, int));
  27. static int  __memp_set_lsn_offset __P((DB_MPOOLFILE *, int32_t));
  28. static int  __memp_set_pgcookie __P((DB_MPOOLFILE *, DBT *));
  29. static int  __memp_set_priority __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY));
  30. static void __memp_set_unlink __P((DB_MPOOLFILE *, int));
  31. /* Initialization methods cannot be called after open is called. */
  32. #define MPF_ILLEGAL_AFTER_OPEN(dbmfp, name)
  33. if (F_ISSET(dbmfp, MP_OPEN_CALLED))
  34. return (__db_mi_open((dbmfp)->dbmp->dbenv, name, 1));
  35. /*
  36.  * __memp_fcreate --
  37.  * Create a DB_MPOOLFILE handle.
  38.  *
  39.  * PUBLIC: int __memp_fcreate __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t));
  40.  */
  41. int
  42. __memp_fcreate(dbenv, retp, flags)
  43. DB_ENV *dbenv;
  44. DB_MPOOLFILE **retp;
  45. u_int32_t flags;
  46. {
  47. DB_MPOOL *dbmp;
  48. DB_MPOOLFILE *dbmfp;
  49. int ret;
  50. PANIC_CHECK(dbenv);
  51. ENV_REQUIRES_CONFIG(dbenv,
  52.     dbenv->mp_handle, "memp_fcreate", DB_INIT_MPOOL);
  53. dbmp = dbenv->mp_handle;
  54. /* Validate arguments. */
  55. if ((ret = __db_fchk(dbenv, "memp_fcreate", flags, 0)) != 0)
  56. return (ret);
  57. /* Allocate and initialize the per-process structure. */
  58. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0)
  59. return (ret);
  60. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), &dbmfp->fhp)) != 0)
  61. goto err;
  62. /* Allocate and initialize a mutex if necessary. */
  63. if (F_ISSET(dbenv, DB_ENV_THREAD) &&
  64.     (ret = __db_mutex_setup(dbenv, dbmp->reginfo, &dbmfp->mutexp,
  65.     MUTEX_ALLOC | MUTEX_THREAD)) != 0)
  66. goto err;
  67. dbmfp->ref = 1;
  68. dbmfp->lsn_offset = -1;
  69. dbmfp->dbmp = dbmp;
  70. dbmfp->mfp = INVALID_ROFF;
  71. dbmfp->close = __memp_fclose;
  72. dbmfp->get = __memp_fget;
  73. dbmfp->get_fileid = __memp_get_fileid;
  74. dbmfp->last_pgno = __memp_last_pgno;
  75. dbmfp->open = __memp_fopen;
  76. dbmfp->put = __memp_fput;
  77. dbmfp->refcnt = __memp_refcnt;
  78. dbmfp->set = __memp_fset;
  79. dbmfp->set_clear_len = __memp_set_clear_len;
  80. dbmfp->set_fileid = __memp_set_fileid;
  81. dbmfp->set_ftype = __memp_set_ftype;
  82. dbmfp->set_lsn_offset = __memp_set_lsn_offset;
  83. dbmfp->set_pgcookie = __memp_set_pgcookie;
  84. dbmfp->set_priority = __memp_set_priority;
  85. dbmfp->set_unlink = __memp_set_unlink;
  86. dbmfp->sync = __memp_fsync;
  87. *retp = dbmfp;
  88. return (0);
  89. err: if (dbmfp != NULL) {
  90. if (dbmfp->fhp != NULL)
  91. (void)__os_free(dbenv, dbmfp->fhp);
  92. (void)__os_free(dbenv, dbmfp);
  93. }
  94. return (ret);
  95. }
  96. /*
  97.  * __memp_set_clear_len --
  98.  * Set the clear length.
  99.  */
  100. static int
  101. __memp_set_clear_len(dbmfp, clear_len)
  102. DB_MPOOLFILE *dbmfp;
  103. u_int32_t clear_len;
  104. {
  105. MPF_ILLEGAL_AFTER_OPEN(dbmfp, "set_clear_len");
  106. dbmfp->clear_len = clear_len;
  107. return (0);
  108. }
  109. /*
  110.  * __memp_set_fileid --
  111.  * Set the file ID.
  112.  */
  113. static int
  114. __memp_set_fileid(dbmfp, fileid)
  115. DB_MPOOLFILE *dbmfp;
  116. u_int8_t *fileid;
  117. {
  118. MPF_ILLEGAL_AFTER_OPEN(dbmfp, "set_fileid");
  119. /*
  120.  * XXX
  121.  * This is dangerous -- we're saving the caller's pointer instead
  122.  * of allocating memory and copying the contents.
  123.  */
  124. dbmfp->fileid = fileid;
  125. return (0);
  126. }
  127. /*
  128.  * __memp_set_ftype --
  129.  * Set the file type (as registered).
  130.  */
  131. static int
  132. __memp_set_ftype(dbmfp, ftype)
  133. DB_MPOOLFILE *dbmfp;
  134. int ftype;
  135. {
  136. MPF_ILLEGAL_AFTER_OPEN(dbmfp, "set_ftype");
  137. dbmfp->ftype = ftype;
  138. return (0);
  139. }
  140. /*
  141.  * __memp_set_lsn_offset --
  142.  * Set the page's LSN offset.
  143.  */
  144. static int
  145. __memp_set_lsn_offset(dbmfp, lsn_offset)
  146. DB_MPOOLFILE *dbmfp;
  147. int32_t lsn_offset;
  148. {
  149. MPF_ILLEGAL_AFTER_OPEN(dbmfp, "set_lsn_offset");
  150. dbmfp->lsn_offset = lsn_offset;
  151. return (0);
  152. }
  153. /*
  154.  * __memp_set_pgcookie --
  155.  * Set the pgin/pgout cookie.
  156.  */
  157. static int
  158. __memp_set_pgcookie(dbmfp, pgcookie)
  159. DB_MPOOLFILE *dbmfp;
  160. DBT *pgcookie;
  161. {
  162. MPF_ILLEGAL_AFTER_OPEN(dbmfp, "set_pgcookie");
  163. dbmfp->pgcookie = pgcookie;
  164. return (0);
  165. }
  166. /*
  167.  * __memp_set_priority --
  168.  * Set the cache priority for pages from this file.
  169.  */
  170. static int
  171. __memp_set_priority(dbmfp, priority)
  172. DB_MPOOLFILE *dbmfp;
  173. DB_CACHE_PRIORITY priority;
  174. {
  175. switch (priority) {
  176. case DB_PRIORITY_VERY_LOW:
  177. dbmfp->mfp->priority = MPOOL_PRI_VERY_LOW;
  178. break;
  179. case DB_PRIORITY_LOW:
  180. dbmfp->mfp->priority = MPOOL_PRI_LOW;
  181. break;
  182. case DB_PRIORITY_DEFAULT:
  183. dbmfp->mfp->priority = MPOOL_PRI_DEFAULT;
  184. break;
  185. case DB_PRIORITY_HIGH:
  186. dbmfp->mfp->priority = MPOOL_PRI_HIGH;
  187. break;
  188. case DB_PRIORITY_VERY_HIGH:
  189. dbmfp->mfp->priority = MPOOL_PRI_VERY_HIGH;
  190. break;
  191. default:
  192. __db_err(dbmfp->dbmp->dbenv,
  193.     "Unknown priority value: %d", priority);
  194. return (EINVAL);
  195. }
  196. return (0);
  197. }
  198. /*
  199.  * __memp_fopen --
  200.  * Open a backing file for the memory pool.
  201.  */
  202. static int
  203. __memp_fopen(dbmfp, path, flags, mode, pagesize)
  204. DB_MPOOLFILE *dbmfp;
  205. const char *path;
  206. u_int32_t flags;
  207. int mode;
  208. size_t pagesize;
  209. {
  210. DB_ENV *dbenv;
  211. DB_MPOOL *dbmp;
  212. int ret;
  213. dbmp = dbmfp->dbmp;
  214. dbenv = dbmp->dbenv;
  215. PANIC_CHECK(dbenv);
  216. /* Validate arguments. */
  217. if ((ret = __db_fchk(dbenv, "memp_fopen", flags,
  218.     DB_CREATE | DB_DIRECT | DB_EXTENT |
  219.     DB_NOMMAP | DB_ODDFILESIZE | DB_RDONLY | DB_TRUNCATE)) != 0)
  220. return (ret);
  221. /*
  222.  * Require a non-zero, power-of-two pagesize, smaller than the
  223.  * clear length.
  224.  */
  225. if (pagesize == 0 || !POWER_OF_TWO(pagesize)) {
  226. __db_err(dbenv,
  227.     "memp_fopen: page sizes must be a power-of-2");
  228. return (EINVAL);
  229. }
  230. if (dbmfp->clear_len > pagesize) {
  231. __db_err(dbenv,
  232.     "memp_fopen: clear length larger than page size");
  233. return (EINVAL);
  234. }
  235. /* Read-only checks, and local flag. */
  236. if (LF_ISSET(DB_RDONLY) && path == NULL) {
  237. __db_err(dbenv,
  238.     "memp_fopen: temporary files can't be readonly");
  239. return (EINVAL);
  240. }
  241. return (__memp_fopen_int(dbmfp, NULL, path, flags, mode, pagesize));
  242. }
  243. /*
  244.  * __memp_fopen_int --
  245.  * Open a backing file for the memory pool; internal version.
  246.  *
  247.  * PUBLIC: int __memp_fopen_int __P((DB_MPOOLFILE *,
  248.  * PUBLIC:     MPOOLFILE *, const char *, u_int32_t, int, size_t));
  249.  */
  250. int
  251. __memp_fopen_int(dbmfp, mfp, path, flags, mode, pagesize)
  252. DB_MPOOLFILE *dbmfp;
  253. MPOOLFILE *mfp;
  254. const char *path;
  255. u_int32_t flags;
  256. int mode;
  257. size_t pagesize;
  258. {
  259. DB_ENV *dbenv;
  260. DB_MPOOL *dbmp;
  261. MPOOL *mp;
  262. db_pgno_t last_pgno;
  263. size_t maxmap;
  264. u_int32_t mbytes, bytes, oflags;
  265. int mfp_alloc, ret;
  266. u_int8_t idbuf[DB_FILE_ID_LEN];
  267. char *rpath;
  268. void *p;
  269. dbmp = dbmfp->dbmp;
  270. dbenv = dbmp->dbenv;
  271. mp = dbmp->reginfo[0].primary;
  272. mfp_alloc = ret = 0;
  273. rpath = NULL;
  274. /*
  275.  * Set the page size so os_open can decide whether to turn buffering
  276.  * off if the DB_DIRECT_DB flag is set.
  277.  */
  278. dbmfp->fhp->pagesize = (u_int32_t)pagesize;
  279. /*
  280.  * If it's a temporary file, delay the open until we actually need
  281.  * to write the file, and we know we can't join any existing files.
  282.  */
  283. if (path == NULL)
  284. goto alloc;
  285. /*
  286.  * Get the real name for this file and open it.  If it's a Queue extent
  287.  * file, it may not exist, and that's OK.
  288.  */
  289. oflags = 0;
  290. if (LF_ISSET(DB_CREATE))
  291. oflags |= DB_OSO_CREATE;
  292. if (LF_ISSET(DB_DIRECT))
  293. oflags |= DB_OSO_DIRECT;
  294. if (LF_ISSET(DB_RDONLY)) {
  295. F_SET(dbmfp, MP_READONLY);
  296. oflags |= DB_OSO_RDONLY;
  297. }
  298. if ((ret =
  299.     __db_appname(dbenv, DB_APP_DATA, path, 0, NULL, &rpath)) != 0)
  300. goto err;
  301. if ((ret = __os_open(dbenv, rpath, oflags, mode, dbmfp->fhp)) != 0) {
  302. if (!LF_ISSET(DB_EXTENT))
  303. __db_err(dbenv, "%s: %s", rpath, db_strerror(ret));
  304. goto err;
  305. }
  306. /*
  307.  * Figure out the file's size.
  308.  *
  309.  * !!!
  310.  * We can't use off_t's here, or in any code in the mainline library
  311.  * for that matter.  (We have to use them in the os stubs, of course,
  312.  * as there are system calls that take them as arguments.)  The reason
  313.  * is some customers build in environments where an off_t is 32-bits,
  314.  * but still run where offsets are 64-bits, and they pay us a lot of
  315.  * money.
  316.  */
  317. if ((ret = __os_ioinfo(
  318.     dbenv, rpath, dbmfp->fhp, &mbytes, &bytes, NULL)) != 0) {
  319. __db_err(dbenv, "%s: %s", rpath, db_strerror(ret));
  320. goto err;
  321. }
  322. /*
  323.  * Get the file id if we weren't given one.  Generated file id's
  324.  * don't use timestamps, otherwise there'd be no chance of any
  325.  * other process joining the party.
  326.  */
  327. if (dbmfp->fileid == NULL) {
  328. if ((ret = __os_fileid(dbenv, rpath, 0, idbuf)) != 0)
  329. goto err;
  330. dbmfp->fileid = idbuf;
  331. }
  332. /*
  333.  * If our caller knows what mfp we're using, increment the ref count,
  334.  * no need to search.
  335.  *
  336.  * We don't need to acquire a lock other than the mfp itself, because
  337.  * we know there's another reference and it's not going away.
  338.  */
  339. if (mfp != NULL) {
  340. MUTEX_LOCK(dbenv, &mfp->mutex);
  341. ++mfp->mpf_cnt;
  342. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  343. goto check_map;
  344. }
  345. /*
  346.  * If not creating a temporary file, walk the list of MPOOLFILE's,
  347.  * looking for a matching file.  Files backed by temporary files
  348.  * or previously removed files can't match.
  349.  *
  350.  * DB_TRUNCATE support.
  351.  *
  352.  * The fileID is a filesystem unique number (e.g., a UNIX dev/inode
  353.  * pair) plus a timestamp.  If files are removed and created in less
  354.  * than a second, the fileID can be repeated.  The problem with
  355.  * repetition happens when the file that previously had the fileID
  356.  * value still has pages in the pool, since we don't want to use them
  357.  * to satisfy requests for the new file.
  358.  *
  359.  * Because the DB_TRUNCATE flag reuses the dev/inode pair, repeated
  360.  * opens with that flag set guarantees matching fileIDs when the
  361.  * machine can open a file and then re-open with truncate within a
  362.  * second.  For this reason, we pass that flag down, and, if we find
  363.  * a matching entry, we ensure that it's never found again, and we
  364.  * create a new entry for the current request.
  365.  */
  366. R_LOCK(dbenv, dbmp->reginfo);
  367. for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
  368.     mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
  369. /* Skip dead files and temporary files. */
  370. if (F_ISSET(mfp, MP_DEADFILE | MP_TEMP))
  371. continue;
  372. /* Skip non-matching files. */
  373. if (memcmp(dbmfp->fileid, R_ADDR(dbmp->reginfo,
  374.     mfp->fileid_off), DB_FILE_ID_LEN) != 0)
  375. continue;
  376. /*
  377.  * If the file is being truncated, remove it from the system
  378.  * and create a new entry.
  379.  *
  380.  * !!!
  381.  * We should be able to set mfp to NULL and break out of the
  382.  * loop, but I like the idea of checking all the entries.
  383.  */
  384. if (LF_ISSET(DB_TRUNCATE)) {
  385. MUTEX_LOCK(dbenv, &mfp->mutex);
  386. MPOOLFILE_IGNORE(mfp);
  387. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  388. continue;
  389. }
  390. /*
  391.  * Some things about a file cannot be changed: the clear length,
  392.  * page size, or lSN location.
  393.  *
  394.  * The file type can change if the application's pre- and post-
  395.  * processing needs change.  For example, an application that
  396.  * created a hash subdatabase in a database that was previously
  397.  * all btree.
  398.  *
  399.  * XXX
  400.  * We do not check to see if the pgcookie information changed,
  401.  * or update it if it is, this might be a bug.
  402.  */
  403. if (dbmfp->clear_len != mfp->clear_len ||
  404.     pagesize != mfp->stat.st_pagesize ||
  405.     dbmfp->lsn_offset != mfp->lsn_off) {
  406. __db_err(dbenv,
  407.     "%s: clear length, page size or LSN location changed",
  408.     path);
  409. R_UNLOCK(dbenv, dbmp->reginfo);
  410. ret = EINVAL;
  411. goto err;
  412. }
  413. if (dbmfp->ftype != 0)
  414. mfp->ftype = dbmfp->ftype;
  415. MUTEX_LOCK(dbenv, &mfp->mutex);
  416. ++mfp->mpf_cnt;
  417. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  418. break;
  419. }
  420. R_UNLOCK(dbenv, dbmp->reginfo);
  421. if (mfp != NULL)
  422. goto check_map;
  423. alloc: /* Allocate and initialize a new MPOOLFILE. */
  424. if ((ret = __memp_alloc(
  425.     dbmp, dbmp->reginfo, NULL, sizeof(MPOOLFILE), NULL, &mfp)) != 0)
  426. goto err;
  427. mfp_alloc = 1;
  428. memset(mfp, 0, sizeof(MPOOLFILE));
  429. mfp->mpf_cnt = 1;
  430. mfp->ftype = dbmfp->ftype;
  431. mfp->stat.st_pagesize = pagesize;
  432. mfp->lsn_off = dbmfp->lsn_offset;
  433. mfp->clear_len = dbmfp->clear_len;
  434. if (LF_ISSET(DB_DIRECT))
  435. F_SET(mfp, MP_DIRECT);
  436. if (LF_ISSET(DB_EXTENT))
  437. F_SET(mfp, MP_EXTENT);
  438. F_SET(mfp, MP_CAN_MMAP);
  439. if (path == NULL)
  440. F_SET(mfp, MP_TEMP);
  441. else {
  442. /*
  443.  * Don't permit files that aren't a multiple of the pagesize,
  444.  * and find the number of the last page in the file, all the
  445.  * time being careful not to overflow 32 bits.
  446.  *
  447.  * During verify or recovery, we might have to cope with a
  448.  * truncated file; if the file size is not a multiple of the
  449.  * page size, round down to a page, we'll take care of the
  450.  * partial page outside the mpool system.
  451.  */
  452. if (bytes % pagesize != 0) {
  453. if (LF_ISSET(DB_ODDFILESIZE))
  454. bytes -= (u_int32_t)(bytes % pagesize);
  455. else {
  456. __db_err(dbenv,
  457.     "%s: file size not a multiple of the pagesize", rpath);
  458. ret = EINVAL;
  459. goto err;
  460. }
  461. }
  462. /*
  463.  * If the user specifies DB_MPOOL_LAST or DB_MPOOL_NEW on a
  464.  * page get, we have to increment the last page in the file.
  465.  * Figure it out and save it away.
  466.  *
  467.  * Note correction: page numbers are zero-based, not 1-based.
  468.  */
  469. last_pgno = (db_pgno_t)(mbytes * (MEGABYTE / pagesize));
  470. last_pgno += (db_pgno_t)(bytes / pagesize);
  471. if (last_pgno != 0)
  472. --last_pgno;
  473. mfp->orig_last_pgno = mfp->last_pgno = last_pgno;
  474. /* Copy the file path into shared memory. */
  475. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  476.     NULL, strlen(path) + 1, &mfp->path_off, &p)) != 0)
  477. goto err;
  478. memcpy(p, path, strlen(path) + 1);
  479. /* Copy the file identification string into shared memory. */
  480. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  481.     NULL, DB_FILE_ID_LEN, &mfp->fileid_off, &p)) != 0)
  482. goto err;
  483. memcpy(p, dbmfp->fileid, DB_FILE_ID_LEN);
  484. }
  485. /* Copy the page cookie into shared memory. */
  486. if (dbmfp->pgcookie == NULL || dbmfp->pgcookie->size == 0) {
  487. mfp->pgcookie_len = 0;
  488. mfp->pgcookie_off = 0;
  489. } else {
  490. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  491.     NULL, dbmfp->pgcookie->size, &mfp->pgcookie_off, &p)) != 0)
  492. goto err;
  493. memcpy(p, dbmfp->pgcookie->data, dbmfp->pgcookie->size);
  494. mfp->pgcookie_len = dbmfp->pgcookie->size;
  495. }
  496. /*
  497.  * Prepend the MPOOLFILE to the list of MPOOLFILE's.
  498.  */
  499. R_LOCK(dbenv, dbmp->reginfo);
  500. ret = __db_mutex_setup(dbenv, dbmp->reginfo, &mfp->mutex,
  501.     MUTEX_NO_RLOCK);
  502. if (ret == 0)
  503. SH_TAILQ_INSERT_HEAD(&mp->mpfq, mfp, q, __mpoolfile);
  504. R_UNLOCK(dbenv, dbmp->reginfo);
  505. if (ret != 0)
  506. goto err;
  507. check_map:
  508. /*
  509.  * If a file:
  510.  * + isn't temporary
  511.  * + is read-only
  512.  * + doesn't require any pgin/pgout support
  513.  * + the DB_NOMMAP flag wasn't set (in either the file open or
  514.  *   the environment in which it was opened)
  515.  * + and is less than mp_mmapsize bytes in size
  516.  *
  517.  * we can mmap it instead of reading/writing buffers.  Don't do error
  518.  * checking based on the mmap call failure.  We want to do normal I/O
  519.  * on the file if the reason we failed was because the file was on an
  520.  * NFS mounted partition, and we can fail in buffer I/O just as easily
  521.  * as here.
  522.  *
  523.  * We'd like to test to see if the file is too big to mmap.  Since we
  524.  * don't know what size or type off_t's or size_t's are, or the largest
  525.  * unsigned integral type is, or what random insanity the local C
  526.  * compiler will perpetrate, doing the comparison in a portable way is
  527.  * flatly impossible.  Hope that mmap fails if the file is too large.
  528.  */
  529. #define DB_MAXMMAPSIZE (10 * 1024 * 1024) /* 10 MB. */
  530. if (F_ISSET(mfp, MP_CAN_MMAP)) {
  531. if (path == NULL)
  532. F_CLR(mfp, MP_CAN_MMAP);
  533. if (!F_ISSET(dbmfp, MP_READONLY))
  534. F_CLR(mfp, MP_CAN_MMAP);
  535. if (dbmfp->ftype != 0)
  536. F_CLR(mfp, MP_CAN_MMAP);
  537. if (LF_ISSET(DB_NOMMAP) || F_ISSET(dbenv, DB_ENV_NOMMAP))
  538. F_CLR(mfp, MP_CAN_MMAP);
  539. maxmap = dbenv->mp_mmapsize == 0 ?
  540.     DB_MAXMMAPSIZE : dbenv->mp_mmapsize;
  541. if (mbytes > maxmap / MEGABYTE ||
  542.     (mbytes == maxmap / MEGABYTE && bytes >= maxmap % MEGABYTE))
  543. F_CLR(mfp, MP_CAN_MMAP);
  544. dbmfp->addr = NULL;
  545. if (F_ISSET(mfp, MP_CAN_MMAP)) {
  546. dbmfp->len = (size_t)mbytes * MEGABYTE + bytes;
  547. if (__os_mapfile(dbenv, rpath,
  548.     dbmfp->fhp, dbmfp->len, 1, &dbmfp->addr) != 0) {
  549. dbmfp->addr = NULL;
  550. F_CLR(mfp, MP_CAN_MMAP);
  551. }
  552. }
  553. }
  554. dbmfp->mfp = mfp;
  555. F_SET(dbmfp, MP_OPEN_CALLED);
  556. /* Add the file to the process' list of DB_MPOOLFILEs. */
  557. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  558. TAILQ_INSERT_TAIL(&dbmp->dbmfq, dbmfp, q);
  559. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  560. if (0) {
  561. err: if (F_ISSET(dbmfp->fhp, DB_FH_VALID))
  562. (void)__os_closehandle(dbenv, dbmfp->fhp);
  563. if (mfp_alloc) {
  564. R_LOCK(dbenv, dbmp->reginfo);
  565. if (mfp->path_off != 0)
  566. __db_shalloc_free(dbmp->reginfo[0].addr,
  567.     R_ADDR(dbmp->reginfo, mfp->path_off));
  568. if (mfp->fileid_off != 0)
  569. __db_shalloc_free(dbmp->reginfo[0].addr,
  570.     R_ADDR(dbmp->reginfo, mfp->fileid_off));
  571. __db_shalloc_free(dbmp->reginfo[0].addr, mfp);
  572. R_UNLOCK(dbenv, dbmp->reginfo);
  573. }
  574. }
  575. if (rpath != NULL)
  576. __os_free(dbenv, rpath);
  577. return (ret);
  578. }
  579. /*
  580.  * __memp_get_fileid --
  581.  * Return the file ID.
  582.  *
  583.  * XXX
  584.  * Undocumented interface: DB private.
  585.  */
  586. static void
  587. __memp_get_fileid(dbmfp, fidp)
  588. DB_MPOOLFILE *dbmfp;
  589. u_int8_t *fidp;
  590. {
  591. /*
  592.  * No lock needed -- we're using the handle, it had better not
  593.  * be going away.
  594.  *
  595.  * !!!
  596.  * Get the fileID out of the region, not out of the DB_MPOOLFILE
  597.  * structure because the DB_MPOOLFILE reference is possibly short
  598.  * lived, and isn't to be trusted.
  599.  */
  600. memcpy(fidp, R_ADDR(
  601.     dbmfp->dbmp->reginfo, dbmfp->mfp->fileid_off), DB_FILE_ID_LEN);
  602. }
  603. /*
  604.  * __memp_last_pgno --
  605.  * Return the page number of the last page in the file.
  606.  *
  607.  * XXX
  608.  * Undocumented interface: DB private.
  609.  */
  610. static void
  611. __memp_last_pgno(dbmfp, pgnoaddr)
  612. DB_MPOOLFILE *dbmfp;
  613. db_pgno_t *pgnoaddr;
  614. {
  615. DB_ENV *dbenv;
  616. DB_MPOOL *dbmp;
  617. dbmp = dbmfp->dbmp;
  618. dbenv = dbmp->dbenv;
  619. R_LOCK(dbenv, dbmp->reginfo);
  620. *pgnoaddr = dbmfp->mfp->last_pgno;
  621. R_UNLOCK(dbenv, dbmp->reginfo);
  622. }
  623. /*
  624.  * __memp_refcnt --
  625.  * Return the current reference count.
  626.  *
  627.  * XXX
  628.  * Undocumented interface: DB private.
  629.  */
  630. static void
  631. __memp_refcnt(dbmfp, cntp)
  632. DB_MPOOLFILE *dbmfp;
  633. db_pgno_t *cntp;
  634. {
  635. DB_ENV *dbenv;
  636. dbenv = dbmfp->dbmp->dbenv;
  637. MUTEX_LOCK(dbenv, &dbmfp->mfp->mutex);
  638. *cntp = dbmfp->mfp->mpf_cnt;
  639. MUTEX_UNLOCK(dbenv, &dbmfp->mfp->mutex);
  640. }
  641. /*
  642.  * __memp_set_unlink --
  643.  * Set unlink on last close flag.
  644.  *
  645.  * XXX
  646.  * Undocumented interface: DB private.
  647.  */
  648. static void
  649. __memp_set_unlink(dbmpf, set)
  650. DB_MPOOLFILE *dbmpf;
  651. int set;
  652. {
  653. DB_ENV *dbenv;
  654. dbenv = dbmpf->dbmp->dbenv;
  655. MUTEX_LOCK(dbenv, &dbmpf->mfp->mutex);
  656. if (set)
  657. F_SET(dbmpf->mfp, MP_UNLINK);
  658. else
  659. F_CLR(dbmpf->mfp, MP_UNLINK);
  660. MUTEX_UNLOCK(dbenv, &dbmpf->mfp->mutex);
  661. }
  662. /*
  663.  * memp_fclose --
  664.  * Close a backing file for the memory pool.
  665.  */
  666. static int
  667. __memp_fclose(dbmfp, flags)
  668. DB_MPOOLFILE *dbmfp;
  669. u_int32_t flags;
  670. {
  671. DB_ENV *dbenv;
  672. int ret, t_ret;
  673. dbenv = dbmfp->dbmp->dbenv;
  674. PANIC_CHECK(dbenv);
  675. /*
  676.  * XXX
  677.  * DB_MPOOL_DISCARD: Undocumented flag: DB private.
  678.  */
  679. ret = __db_fchk(dbenv, "DB_MPOOLFILE->close", flags, DB_MPOOL_DISCARD);
  680. if ((t_ret = __memp_fclose_int(dbmfp, flags)) != 0 && ret == 0)
  681. ret = t_ret;
  682. return (ret);
  683. }
  684. /*
  685.  * __memp_fclose_int --
  686.  * Internal version of __memp_fclose.
  687.  *
  688.  * PUBLIC: int __memp_fclose_int __P((DB_MPOOLFILE *, u_int32_t));
  689.  */
  690. int
  691. __memp_fclose_int(dbmfp, flags)
  692. DB_MPOOLFILE *dbmfp;
  693. u_int32_t flags;
  694. {
  695. DB_ENV *dbenv;
  696. DB_MPOOL *dbmp;
  697. MPOOLFILE *mfp;
  698. char *rpath;
  699. int deleted, ret, t_ret;
  700. dbmp = dbmfp->dbmp;
  701. dbenv = dbmp->dbenv;
  702. ret = 0;
  703. /*
  704.  * We have to reference count DB_MPOOLFILE structures as other threads
  705.  * in the process may be using them.  Here's the problem:
  706.  *
  707.  * Thread A opens a database.
  708.  * Thread B uses thread A's DB_MPOOLFILE to write a buffer
  709.  *    in order to free up memory in the mpool cache.
  710.  * Thread A closes the database while thread B is using the
  711.  *    DB_MPOOLFILE structure.
  712.  *
  713.  * By opening all databases before creating any threads, and closing
  714.  * the databases after all the threads have exited, applications get
  715.  * better performance and avoid the problem path entirely.
  716.  *
  717.  * Regardless, holding the DB_MPOOLFILE to flush a dirty buffer is a
  718.  * short-term lock, even in worst case, since we better be the only
  719.  * thread of control using the DB_MPOOLFILE structure to read pages
  720.  * *into* the cache.  Wait until we're the only reference holder and
  721.  * remove the DB_MPOOLFILE structure from the list, so nobody else can
  722.  * find it.  We do this, rather than have the last reference holder
  723.  * (whoever that might be) discard the DB_MPOOLFILE structure, because
  724.  * we'd rather write error messages to the application in the close
  725.  * routine, not in the checkpoint/sync routine.
  726.  *
  727.  * !!!
  728.  * It's possible the DB_MPOOLFILE was never added to the DB_MPOOLFILE
  729.  * file list, check the DB_OPEN_CALLED flag to be sure.
  730.  */
  731. for (deleted = 0;;) {
  732. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  733. if (dbmfp->ref == 1) {
  734. if (F_ISSET(dbmfp, MP_OPEN_CALLED))
  735. TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q);
  736. deleted = 1;
  737. }
  738. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  739. if (deleted)
  740. break;
  741. __os_sleep(dbenv, 1, 0);
  742. }
  743. /* Complain if pinned blocks never returned. */
  744. if (dbmfp->pinref != 0) {
  745. __db_err(dbenv, "%s: close: %lu blocks left pinned",
  746.     __memp_fn(dbmfp), (u_long)dbmfp->pinref);
  747. ret = __db_panic(dbenv, DB_RUNRECOVERY);
  748. }
  749. /* Discard any mmap information. */
  750. if (dbmfp->addr != NULL &&
  751.     (ret = __os_unmapfile(dbenv, dbmfp->addr, dbmfp->len)) != 0)
  752. __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(ret));
  753. /* Close the file; temporary files may not yet have been created. */
  754. if (F_ISSET(dbmfp->fhp, DB_FH_VALID) &&
  755.     (t_ret = __os_closehandle(dbenv, dbmfp->fhp)) != 0) {
  756. __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(t_ret));
  757. if (ret == 0)
  758. ret = t_ret;
  759. }
  760. /* Discard the thread mutex. */
  761. if (dbmfp->mutexp != NULL)
  762. __db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp);
  763. /*
  764.  * Discard our reference on the the underlying MPOOLFILE, and close
  765.  * it if it's no longer useful to anyone.  It possible the open of
  766.  * the file never happened or wasn't successful, in which case, mpf
  767.  * will be NULL;
  768.  */
  769. if ((mfp = dbmfp->mfp) == NULL)
  770. goto done;
  771. /*
  772.  * If it's a temp file, all outstanding references belong to unflushed
  773.  * buffers.  (A temp file can only be referenced by one DB_MPOOLFILE).
  774.  * We don't care about preserving any of those buffers, so mark the
  775.  * MPOOLFILE as dead so that even the dirty ones just get discarded
  776.  * when we try to flush them.
  777.  */
  778. deleted = 0;
  779. MUTEX_LOCK(dbenv, &mfp->mutex);
  780. if (--mfp->mpf_cnt == 0 || LF_ISSET(DB_MPOOL_DISCARD)) {
  781. if (LF_ISSET(DB_MPOOL_DISCARD) ||
  782.     F_ISSET(mfp, MP_TEMP | MP_UNLINK))
  783. MPOOLFILE_IGNORE(mfp);
  784. if (F_ISSET(mfp, MP_UNLINK)) {
  785. if ((t_ret = __db_appname(dbmp->dbenv,
  786.     DB_APP_DATA, R_ADDR(dbmp->reginfo,
  787.     mfp->path_off), 0, NULL, &rpath)) != 0 && ret == 0)
  788. ret = t_ret;
  789. if (t_ret == 0) {
  790. if ((t_ret = __os_unlink(
  791.     dbmp->dbenv, rpath) != 0) && ret == 0)
  792. ret = t_ret;
  793. __os_free(dbenv, rpath);
  794. }
  795. }
  796. if (mfp->block_cnt == 0) {
  797. if ((t_ret =
  798.     __memp_mf_discard(dbmp, mfp)) != 0 && ret == 0)
  799. ret = t_ret;
  800. deleted = 1;
  801. }
  802. }
  803. if (deleted == 0)
  804. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  805. /* Discard the DB_MPOOLFILE structure. */
  806. done: __os_free(dbenv, dbmfp->fhp);
  807. __os_free(dbenv, dbmfp);
  808. return (ret);
  809. }
  810. /*
  811.  * __memp_mf_discard --
  812.  * Discard an MPOOLFILE.
  813.  *
  814.  * PUBLIC: int __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *));
  815.  */
  816. int
  817. __memp_mf_discard(dbmp, mfp)
  818. DB_MPOOL *dbmp;
  819. MPOOLFILE *mfp;
  820. {
  821. DB_ENV *dbenv;
  822. DB_FH fh;
  823. DB_MPOOL_STAT *sp;
  824. MPOOL *mp;
  825. char *rpath;
  826. int ret;
  827. dbenv = dbmp->dbenv;
  828. mp = dbmp->reginfo[0].primary;
  829. ret = 0;
  830. /*
  831.  * Expects caller to be holding the MPOOLFILE mutex.
  832.  *
  833.  * When discarding a file, we have to flush writes from it to disk.
  834.  * The scenario is that dirty buffers from this file need to be
  835.  * flushed to satisfy a future checkpoint, but when the checkpoint
  836.  * calls mpool sync, the sync code won't know anything about them.
  837.  */
  838. if (!F_ISSET(mfp, MP_DEADFILE) &&
  839.     (ret = __db_appname(dbenv, DB_APP_DATA,
  840.     R_ADDR(dbmp->reginfo, mfp->path_off), 0, NULL, &rpath)) == 0) {
  841. if ((ret = __os_open(dbenv, rpath, 0, 0, &fh)) == 0) {
  842. ret = __os_fsync(dbenv, &fh);
  843. (void)__os_closehandle(dbenv, &fh);
  844. }
  845. __os_free(dbenv, rpath);
  846. }
  847. /*
  848.  * We have to release the MPOOLFILE lock before acquiring the region
  849.  * lock so that we don't deadlock.  Make sure nobody ever looks at
  850.  * this structure again.
  851.  */
  852. MPOOLFILE_IGNORE(mfp);
  853. /* Discard the mutex we're holding. */
  854. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  855. /* Delete from the list of MPOOLFILEs. */
  856. R_LOCK(dbenv, dbmp->reginfo);
  857. SH_TAILQ_REMOVE(&mp->mpfq, mfp, q, __mpoolfile);
  858. /* Copy the statistics into the region. */
  859. sp = &mp->stat;
  860. sp->st_cache_hit += mfp->stat.st_cache_hit;
  861. sp->st_cache_miss += mfp->stat.st_cache_miss;
  862. sp->st_map += mfp->stat.st_map;
  863. sp->st_page_create += mfp->stat.st_page_create;
  864. sp->st_page_in += mfp->stat.st_page_in;
  865. sp->st_page_out += mfp->stat.st_page_out;
  866. /* Clear the mutex this MPOOLFILE recorded. */
  867. __db_shlocks_clear(&mfp->mutex, dbmp->reginfo,
  868.     (REGMAINT *)R_ADDR(dbmp->reginfo, mp->maint_off));
  869. /* Free the space. */
  870. if (mfp->path_off != 0)
  871. __db_shalloc_free(dbmp->reginfo[0].addr,
  872.     R_ADDR(dbmp->reginfo, mfp->path_off));
  873. if (mfp->fileid_off != 0)
  874. __db_shalloc_free(dbmp->reginfo[0].addr,
  875.     R_ADDR(dbmp->reginfo, mfp->fileid_off));
  876. if (mfp->pgcookie_off != 0)
  877. __db_shalloc_free(dbmp->reginfo[0].addr,
  878.     R_ADDR(dbmp->reginfo, mfp->pgcookie_off));
  879. __db_shalloc_free(dbmp->reginfo[0].addr, mfp);
  880. R_UNLOCK(dbenv, dbmp->reginfo);
  881. return (ret);
  882. }
  883. /*
  884.  * __memp_fn --
  885.  * On errors we print whatever is available as the file name.
  886.  *
  887.  * PUBLIC: char * __memp_fn __P((DB_MPOOLFILE *));
  888.  */
  889. char *
  890. __memp_fn(dbmfp)
  891. DB_MPOOLFILE *dbmfp;
  892. {
  893. return (__memp_fns(dbmfp->dbmp, dbmfp->mfp));
  894. }
  895. /*
  896.  * __memp_fns --
  897.  * On errors we print whatever is available as the file name.
  898.  *
  899.  * PUBLIC: char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *));
  900.  *
  901.  */
  902. char *
  903. __memp_fns(dbmp, mfp)
  904. DB_MPOOL *dbmp;
  905. MPOOLFILE *mfp;
  906. {
  907. if (mfp->path_off == 0)
  908. return ((char *)"temporary");
  909. return ((char *)R_ADDR(dbmp->reginfo, mfp->path_off));
  910. }