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

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_bh.c,v 11.71 2002/09/04 19:06:45 margo Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "dbinc/db_shash.h"
  18. #include "dbinc/mp.h"
  19. #include "dbinc/log.h"
  20. #include "dbinc/db_page.h"
  21. static int __memp_pgwrite
  22.    __P((DB_MPOOL *, DB_MPOOLFILE *, DB_MPOOL_HASH *, BH *));
  23. static int __memp_upgrade __P((DB_MPOOL *, DB_MPOOLFILE *, MPOOLFILE *));
  24. /*
  25.  * __memp_bhwrite --
  26.  * Write the page associated with a given buffer header.
  27.  *
  28.  * PUBLIC: int __memp_bhwrite __P((DB_MPOOL *,
  29.  * PUBLIC:      DB_MPOOL_HASH *, MPOOLFILE *, BH *, int));
  30.  */
  31. int
  32. __memp_bhwrite(dbmp, hp, mfp, bhp, open_extents)
  33. DB_MPOOL *dbmp;
  34. DB_MPOOL_HASH *hp;
  35. MPOOLFILE *mfp;
  36. BH *bhp;
  37. int open_extents;
  38. {
  39. DB_ENV *dbenv;
  40. DB_MPOOLFILE *dbmfp;
  41. DB_MPREG *mpreg;
  42. int local_open, incremented, ret;
  43. dbenv = dbmp->dbenv;
  44. local_open = incremented = 0;
  45. /*
  46.  * If the file has been removed or is a closed temporary file, jump
  47.  * right ahead and pretend that we've found the file we want -- the
  48.  * page-write function knows how to handle the fact that we don't have
  49.  * (or need!) any real file descriptor information.
  50.  */
  51. if (F_ISSET(mfp, MP_DEADFILE)) {
  52. dbmfp = NULL;
  53. goto found;
  54. }
  55. /*
  56.  * Walk the process' DB_MPOOLFILE list and find a file descriptor for
  57.  * the file.  We also check that the descriptor is open for writing.
  58.  * If we find a descriptor on the file that's not open for writing, we
  59.  * try and upgrade it to make it writeable.  If that fails, we're done.
  60.  */
  61. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  62. for (dbmfp = TAILQ_FIRST(&dbmp->dbmfq);
  63.     dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q))
  64. if (dbmfp->mfp == mfp) {
  65. if (F_ISSET(dbmfp, MP_READONLY) &&
  66.     !F_ISSET(dbmfp, MP_UPGRADE) &&
  67.     (F_ISSET(dbmfp, MP_UPGRADE_FAIL) ||
  68.     __memp_upgrade(dbmp, dbmfp, mfp))) {
  69. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  70. return (EPERM);
  71. }
  72. /*
  73.  * Increment the reference count -- see the comment in
  74.  * __memp_fclose_int().
  75.  */
  76. ++dbmfp->ref;
  77. incremented = 1;
  78. break;
  79. }
  80. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  81. if (dbmfp != NULL)
  82. goto found;
  83. /*
  84.  * !!!
  85.  * It's the caller's choice if we're going to open extent files.
  86.  */
  87. if (!open_extents && F_ISSET(mfp, MP_EXTENT))
  88. return (EPERM);
  89. /*
  90.  * !!!
  91.  * Don't try to attach to temporary files.  There are two problems in
  92.  * trying to do that.  First, if we have different privileges than the
  93.  * process that "owns" the temporary file, we might create the backing
  94.  * disk file such that the owning process couldn't read/write its own
  95.  * buffers, e.g., memp_trickle running as root creating a file owned
  96.  * as root, mode 600.  Second, if the temporary file has already been
  97.  * created, we don't have any way of finding out what its real name is,
  98.  * and, even if we did, it was already unlinked (so that it won't be
  99.  * left if the process dies horribly).  This decision causes a problem,
  100.  * however: if the temporary file consumes the entire buffer cache,
  101.  * and the owner doesn't flush the buffers to disk, we could end up
  102.  * with resource starvation, and the memp_trickle thread couldn't do
  103.  * anything about it.  That's a pretty unlikely scenario, though.
  104.  *
  105.  * Note we should never get here when the temporary file in question
  106.  * has already been closed in another process, in which case it should
  107.  * be marked MP_DEADFILE.
  108.  */
  109. if (F_ISSET(mfp, MP_TEMP))
  110. return (EPERM);
  111. /*
  112.  * It's not a page from a file we've opened.  If the file requires
  113.  * input/output processing, see if this process has ever registered
  114.  * information as to how to write this type of file.  If not, there's
  115.  * nothing we can do.
  116.  */
  117. if (mfp->ftype != 0) {
  118. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  119. for (mpreg = LIST_FIRST(&dbmp->dbregq);
  120.     mpreg != NULL; mpreg = LIST_NEXT(mpreg, q))
  121. if (mpreg->ftype == mfp->ftype)
  122. break;
  123. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  124. if (mpreg == NULL)
  125. return (EPERM);
  126. }
  127. /*
  128.  * Try and open the file, attaching to the underlying shared area.
  129.  * Ignore any error, assume it's a permissions problem.
  130.  *
  131.  * XXX
  132.  * There's no negative cache, so we may repeatedly try and open files
  133.  * that we have previously tried (and failed) to open.
  134.  */
  135. if ((ret = dbenv->memp_fcreate(dbenv, &dbmfp, 0)) != 0)
  136. return (ret);
  137. if ((ret = __memp_fopen_int(dbmfp, mfp,
  138.     R_ADDR(dbmp->reginfo, mfp->path_off),
  139.     0, 0, mfp->stat.st_pagesize)) != 0) {
  140. (void)dbmfp->close(dbmfp, 0);
  141. return (ret);
  142. }
  143. local_open = 1;
  144. found: ret = __memp_pgwrite(dbmp, dbmfp, hp, bhp);
  145. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  146. if (incremented)
  147. --dbmfp->ref;
  148. else if (local_open)
  149. F_SET(dbmfp, MP_FLUSH);
  150. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  151. return (ret);
  152. }
  153. /*
  154.  * __memp_pgread --
  155.  * Read a page from a file.
  156.  *
  157.  * PUBLIC: int __memp_pgread __P((DB_MPOOLFILE *, DB_MUTEX *, BH *, int));
  158.  */
  159. int
  160. __memp_pgread(dbmfp, mutexp, bhp, can_create)
  161. DB_MPOOLFILE *dbmfp;
  162. DB_MUTEX *mutexp;
  163. BH *bhp;
  164. int can_create;
  165. {
  166. DB_IO db_io;
  167. DB_ENV *dbenv;
  168. DB_MPOOL *dbmp;
  169. MPOOLFILE *mfp;
  170. size_t len, nr, pagesize;
  171. int ret;
  172. dbmp = dbmfp->dbmp;
  173. dbenv = dbmp->dbenv;
  174. mfp = dbmfp->mfp;
  175. pagesize = mfp->stat.st_pagesize;
  176. /* We should never be called with a dirty or a locked buffer. */
  177. DB_ASSERT(!F_ISSET(bhp, BH_DIRTY | BH_DIRTY_CREATE | BH_LOCKED));
  178. /* Lock the buffer and swap the hash bucket lock for the buffer lock. */
  179. F_SET(bhp, BH_LOCKED | BH_TRASH);
  180. MUTEX_LOCK(dbenv, &bhp->mutex);
  181. MUTEX_UNLOCK(dbenv, mutexp);
  182. /*
  183.  * Temporary files may not yet have been created.  We don't create
  184.  * them now, we create them when the pages have to be flushed.
  185.  */
  186. nr = 0;
  187. if (F_ISSET(dbmfp->fhp, DB_FH_VALID)) {
  188. db_io.fhp = dbmfp->fhp;
  189. db_io.mutexp = dbmfp->mutexp;
  190. db_io.pagesize = db_io.bytes = pagesize;
  191. db_io.pgno = bhp->pgno;
  192. db_io.buf = bhp->buf;
  193. /*
  194.  * The page may not exist; if it doesn't, nr may well be 0,
  195.  * but we expect the underlying OS calls not to return an
  196.  * error code in this case.
  197.  */
  198. if ((ret = __os_io(dbenv, &db_io, DB_IO_READ, &nr)) != 0)
  199. goto err;
  200. }
  201. if (nr < pagesize) {
  202. /*
  203.  * Don't output error messages for short reads.  In particular,
  204.  * DB recovery processing may request pages never written to
  205.  * disk or for which only some part have been written to disk,
  206.  * in which case we won't find the page.  The caller must know
  207.  * how to handle the error.
  208.  */
  209. if (can_create == 0) {
  210. ret = DB_PAGE_NOTFOUND;
  211. goto err;
  212. }
  213. /* Clear any bytes that need to be cleared. */
  214. len = mfp->clear_len == 0 ? pagesize : mfp->clear_len;
  215. memset(bhp->buf, 0, len);
  216. #if defined(DIAGNOSTIC) || defined(UMRW)
  217. /*
  218.  * If we're running in diagnostic mode, corrupt any bytes on
  219.  * the page that are unknown quantities for the caller.
  220.  */
  221. if (len < pagesize)
  222. memset(bhp->buf + len, CLEAR_BYTE, pagesize - len);
  223. #endif
  224. ++mfp->stat.st_page_create;
  225. } else
  226. ++mfp->stat.st_page_in;
  227. /* Call any pgin function. */
  228. ret = mfp->ftype == 0 ? 0 : __memp_pg(dbmfp, bhp, 1);
  229. /* Unlock the buffer and reacquire the hash bucket lock. */
  230. err: MUTEX_UNLOCK(dbenv, &bhp->mutex);
  231. MUTEX_LOCK(dbenv, mutexp);
  232. /*
  233.  * If no errors occurred, the data is now valid, clear the BH_TRASH
  234.  * flag; regardless, clear the lock bit and let other threads proceed.
  235.  */
  236. F_CLR(bhp, BH_LOCKED);
  237. if (ret == 0)
  238. F_CLR(bhp, BH_TRASH);
  239. return (ret);
  240. }
  241. /*
  242.  * __memp_pgwrite --
  243.  * Write a page to a file.
  244.  */
  245. static int
  246. __memp_pgwrite(dbmp, dbmfp, hp, bhp)
  247. DB_MPOOL *dbmp;
  248. DB_MPOOLFILE *dbmfp;
  249. DB_MPOOL_HASH *hp;
  250. BH *bhp;
  251. {
  252. DB_ENV *dbenv;
  253. DB_IO db_io;
  254. DB_LSN lsn;
  255. MPOOLFILE *mfp;
  256. size_t nw;
  257. int callpgin, ret;
  258. dbenv = dbmp->dbenv;
  259. mfp = dbmfp == NULL ? NULL : dbmfp->mfp;
  260. callpgin = ret = 0;
  261. /*
  262.  * We should never be called with a clean or trash buffer.
  263.  * The sync code does call us with already locked buffers.
  264.  */
  265. DB_ASSERT(F_ISSET(bhp, BH_DIRTY));
  266. DB_ASSERT(!F_ISSET(bhp, BH_TRASH));
  267. /*
  268.  * If we have not already traded the hash bucket lock for the buffer
  269.  * lock, do so now.
  270.  */
  271. if (!F_ISSET(bhp, BH_LOCKED)) {
  272. F_SET(bhp, BH_LOCKED);
  273. MUTEX_LOCK(dbenv, &bhp->mutex);
  274. MUTEX_UNLOCK(dbenv, &hp->hash_mutex);
  275. }
  276. /*
  277.  * It's possible that the underlying file doesn't exist, either
  278.  * because of an outright removal or because it was a temporary
  279.  * file that's been closed.
  280.  *
  281.  * !!!
  282.  * Once we pass this point, we know that dbmfp and mfp aren't NULL,
  283.  * and that we have a valid file reference.
  284.  */
  285. if (mfp == NULL || F_ISSET(mfp, MP_DEADFILE))
  286. goto file_dead;
  287. /*
  288.  * If the page is in a file for which we have LSN information, we have
  289.  * to ensure the appropriate log records are on disk.
  290.  */
  291. if (LOGGING_ON(dbenv) && mfp->lsn_off != -1) {
  292. memcpy(&lsn, bhp->buf + mfp->lsn_off, sizeof(DB_LSN));
  293. if ((ret = dbenv->log_flush(dbenv, &lsn)) != 0)
  294. goto err;
  295. }
  296. #ifdef DIAGNOSTIC
  297. /*
  298.  * Verify write-ahead logging semantics.
  299.  *
  300.  * !!!
  301.  * One special case.  There is a single field on the meta-data page,
  302.  * the last-page-number-in-the-file field, for which we do not log
  303.  * changes.  If the page was originally created in a database that
  304.  * didn't have logging turned on, we can see a page marked dirty but
  305.  * for which no corresponding log record has been written.  However,
  306.  * the only way that a page can be created for which there isn't a
  307.  * previous log record and valid LSN is when the page was created
  308.  * without logging turned on, and so we check for that special-case
  309.  * LSN value.
  310.  */
  311. if (LOGGING_ON(dbenv) && !IS_NOT_LOGGED_LSN(LSN(bhp->buf))) {
  312. /*
  313.  * There is a potential race here.  If we are in the midst of
  314.  * switching log files, it's possible we could test against the
  315.  * old file and the new offset in the log region's LSN.  If we
  316.  * fail the first test, acquire the log mutex and check again.
  317.  */
  318. DB_LOG *dblp;
  319. LOG *lp;
  320. dblp = dbenv->lg_handle;
  321. lp = dblp->reginfo.primary;
  322. if (!IS_NOT_LOGGED_LSN(LSN(bhp->buf)) &&
  323.     log_compare(&lp->s_lsn, &LSN(bhp->buf)) <= 0) {
  324. R_LOCK(dbenv, &dblp->reginfo);
  325. DB_ASSERT(log_compare(&lp->s_lsn, &LSN(bhp->buf)) > 0);
  326. R_UNLOCK(dbenv, &dblp->reginfo);
  327. }
  328. }
  329. #endif
  330. /*
  331.  * Call any pgout function.  We set the callpgin flag so that we flag
  332.  * that the contents of the buffer will need to be passed through pgin
  333.  * before they are reused.
  334.  */
  335. if (mfp->ftype != 0) {
  336. callpgin = 1;
  337. if ((ret = __memp_pg(dbmfp, bhp, 0)) != 0)
  338. goto err;
  339. }
  340. /* Temporary files may not yet have been created. */
  341. if (!F_ISSET(dbmfp->fhp, DB_FH_VALID)) {
  342. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  343. ret = F_ISSET(dbmfp->fhp, DB_FH_VALID) ? 0 :
  344.     __db_appname(dbenv, DB_APP_TMP, NULL,
  345.     F_ISSET(dbenv, DB_ENV_DIRECT_DB) ? DB_OSO_DIRECT : 0,
  346.     dbmfp->fhp, NULL);
  347. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  348. if (ret != 0) {
  349. __db_err(dbenv,
  350.     "unable to create temporary backing file");
  351. goto err;
  352. }
  353. }
  354. /* Write the page. */
  355. db_io.fhp = dbmfp->fhp;
  356. db_io.mutexp = dbmfp->mutexp;
  357. db_io.pagesize = db_io.bytes = mfp->stat.st_pagesize;
  358. db_io.pgno = bhp->pgno;
  359. db_io.buf = bhp->buf;
  360. if ((ret = __os_io(dbenv, &db_io, DB_IO_WRITE, &nw)) != 0) {
  361. __db_err(dbenv, "%s: write failed for page %lu",
  362.     __memp_fn(dbmfp), (u_long)bhp->pgno);
  363. goto err;
  364. }
  365. ++mfp->stat.st_page_out;
  366. err:
  367. file_dead:
  368. /*
  369.  * !!!
  370.  * Once we pass this point, dbmfp and mfp may be NULL, we may not have
  371.  * a valid file reference.
  372.  *
  373.  * Unlock the buffer and reacquire the hash lock.
  374.  */
  375. MUTEX_UNLOCK(dbenv, &bhp->mutex);
  376. MUTEX_LOCK(dbenv, &hp->hash_mutex);
  377. /*
  378.  * If we rewrote the page, it will need processing by the pgin
  379.  * routine before reuse.
  380.  */
  381. if (callpgin)
  382. F_SET(bhp, BH_CALLPGIN);
  383. /*
  384.  * Update the hash bucket statistics, reset the flags.
  385.  * If we were successful, the page is no longer dirty.
  386.  */
  387. if (ret == 0) {
  388. DB_ASSERT(hp->hash_page_dirty != 0);
  389. --hp->hash_page_dirty;
  390. F_CLR(bhp, BH_DIRTY | BH_DIRTY_CREATE);
  391. }
  392. /* Regardless, clear any sync wait-for count and remove our lock. */
  393. bhp->ref_sync = 0;
  394. F_CLR(bhp, BH_LOCKED);
  395. return (ret);
  396. }
  397. /*
  398.  * __memp_pg --
  399.  * Call the pgin/pgout routine.
  400.  *
  401.  * PUBLIC: int __memp_pg __P((DB_MPOOLFILE *, BH *, int));
  402.  */
  403. int
  404. __memp_pg(dbmfp, bhp, is_pgin)
  405. DB_MPOOLFILE *dbmfp;
  406. BH *bhp;
  407. int is_pgin;
  408. {
  409. DBT dbt, *dbtp;
  410. DB_ENV *dbenv;
  411. DB_MPOOL *dbmp;
  412. DB_MPREG *mpreg;
  413. MPOOLFILE *mfp;
  414. int ftype, ret;
  415. dbmp = dbmfp->dbmp;
  416. dbenv = dbmp->dbenv;
  417. mfp = dbmfp->mfp;
  418. MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp);
  419. ftype = mfp->ftype;
  420. for (mpreg = LIST_FIRST(&dbmp->dbregq);
  421.     mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) {
  422. if (ftype != mpreg->ftype)
  423. continue;
  424. if (mfp->pgcookie_len == 0)
  425. dbtp = NULL;
  426. else {
  427. dbt.size = mfp->pgcookie_len;
  428. dbt.data = R_ADDR(dbmp->reginfo, mfp->pgcookie_off);
  429. dbtp = &dbt;
  430. }
  431. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  432. if (is_pgin) {
  433. if (mpreg->pgin != NULL &&
  434.     (ret = mpreg->pgin(dbenv,
  435.     bhp->pgno, bhp->buf, dbtp)) != 0)
  436. goto err;
  437. } else
  438. if (mpreg->pgout != NULL &&
  439.     (ret = mpreg->pgout(dbenv,
  440.     bhp->pgno, bhp->buf, dbtp)) != 0)
  441. goto err;
  442. break;
  443. }
  444. if (mpreg == NULL)
  445. MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  446. return (0);
  447. err: MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp);
  448. __db_err(dbenv, "%s: %s failed for page %lu",
  449.     __memp_fn(dbmfp), is_pgin ? "pgin" : "pgout", (u_long)bhp->pgno);
  450. return (ret);
  451. }
  452. /*
  453.  * __memp_bhfree --
  454.  * Free a bucket header and its referenced data.
  455.  *
  456.  * PUBLIC: void __memp_bhfree __P((DB_MPOOL *, DB_MPOOL_HASH *, BH *, int));
  457.  */
  458. void
  459. __memp_bhfree(dbmp, hp, bhp, free_mem)
  460. DB_MPOOL *dbmp;
  461. DB_MPOOL_HASH *hp;
  462. BH *bhp;
  463. int free_mem;
  464. {
  465. DB_ENV *dbenv;
  466. MPOOL *c_mp, *mp;
  467. MPOOLFILE *mfp;
  468. u_int32_t n_cache;
  469. /*
  470.  * Assumes the hash bucket is locked and the MPOOL is not.
  471.  */
  472. dbenv = dbmp->dbenv;
  473. mp = dbmp->reginfo[0].primary;
  474. n_cache = NCACHE(mp, bhp->mf_offset, bhp->pgno);
  475. /*
  476.  * Delete the buffer header from the hash bucket queue and reset
  477.  * the hash bucket's priority, if necessary.
  478.  */
  479. SH_TAILQ_REMOVE(&hp->hash_bucket, bhp, hq, __bh);
  480. if (bhp->priority == hp->hash_priority)
  481. hp->hash_priority =
  482.     SH_TAILQ_FIRST(&hp->hash_bucket, __bh) == NULL ?
  483.     0 : SH_TAILQ_FIRST(&hp->hash_bucket, __bh)->priority;
  484. /*
  485.  * Discard the hash bucket's mutex, it's no longer needed, and
  486.  * we don't want to be holding it when acquiring other locks.
  487.  */
  488. MUTEX_UNLOCK(dbenv, &hp->hash_mutex);
  489. /*
  490.  * Find the underlying MPOOLFILE and decrement its reference count.
  491.  * If this is its last reference, remove it.
  492.  */
  493. mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
  494. MUTEX_LOCK(dbenv, &mfp->mutex);
  495. if (--mfp->block_cnt == 0 && mfp->mpf_cnt == 0)
  496. __memp_mf_discard(dbmp, mfp);
  497. else
  498. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  499. R_LOCK(dbenv, &dbmp->reginfo[n_cache]);
  500. /*
  501.  * Clear the mutex this buffer recorded; requires the region lock
  502.  * be held.
  503.  */
  504. __db_shlocks_clear(&bhp->mutex, &dbmp->reginfo[n_cache],
  505.     (REGMAINT *)R_ADDR(&dbmp->reginfo[n_cache], mp->maint_off));
  506. /*
  507.  * If we're not reusing the buffer immediately, free the buffer header
  508.  * and data for real.
  509.  */
  510. if (free_mem) {
  511. __db_shalloc_free(dbmp->reginfo[n_cache].addr, bhp);
  512. c_mp = dbmp->reginfo[n_cache].primary;
  513. c_mp->stat.st_pages--;
  514. }
  515. R_UNLOCK(dbenv, &dbmp->reginfo[n_cache]);
  516. }
  517. /*
  518.  * __memp_upgrade --
  519.  * Upgrade a file descriptor from read-only to read-write.
  520.  */
  521. static int
  522. __memp_upgrade(dbmp, dbmfp, mfp)
  523. DB_MPOOL *dbmp;
  524. DB_MPOOLFILE *dbmfp;
  525. MPOOLFILE *mfp;
  526. {
  527. DB_ENV *dbenv;
  528. DB_FH *fhp, *tfhp;
  529. int ret;
  530. char *rpath;
  531. dbenv = dbmp->dbenv;
  532. fhp = NULL;
  533. rpath = NULL;
  534. /*
  535.  * Calculate the real name for this file and try to open it read/write.
  536.  * We know we have a valid pathname for the file because it's the only
  537.  * way we could have gotten a file descriptor of any kind.
  538.  */
  539. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), &fhp)) != 0)
  540. goto err;
  541. if ((ret = __db_appname(dbenv, DB_APP_DATA,
  542.     R_ADDR(dbmp->reginfo, mfp->path_off), 0, NULL, &rpath)) != 0)
  543. goto err;
  544. if (__os_open(dbenv, rpath,
  545.     F_ISSET(mfp, MP_DIRECT) ? DB_OSO_DIRECT : 0, 0, fhp) != 0) {
  546. F_SET(dbmfp, MP_UPGRADE_FAIL);
  547. goto err;
  548. }
  549. /*
  550.  * Swap the descriptors and set the upgrade flag.
  551.  *
  552.  * XXX
  553.  * There is a race here.  If another process schedules a read using the
  554.  * existing file descriptor and is swapped out before making the system
  555.  * call, this code could theoretically close the file descriptor out
  556.  * from under it.  While it's very unlikely, this code should still be
  557.  * rewritten.
  558.  */
  559. tfhp = dbmfp->fhp;
  560. dbmfp->fhp = fhp;
  561. fhp = tfhp;
  562. (void)__os_closehandle(dbenv, fhp);
  563. F_SET(dbmfp, MP_UPGRADE);
  564. ret = 0;
  565. if (0) {
  566. err: ret = 1;
  567. }
  568. if (fhp != NULL)
  569. __os_free(dbenv, fhp);
  570. if (rpath != NULL)
  571. __os_free(dbenv, rpath);
  572. return (ret);
  573. }