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

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: env_region.c,v 11.28 2000/12/12 17:36:10 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "db_shash.h"
  19. #include "lock.h"
  20. #include "lock_ext.h"
  21. #include "log.h"
  22. #include "log_ext.h"
  23. #include "mp.h"
  24. #include "mp_ext.h"
  25. #include "txn.h"
  26. #include "txn_ext.h"
  27. static int  __db_des_destroy __P((DB_ENV *, REGION *));
  28. static int  __db_des_get __P((DB_ENV *, REGINFO *, REGINFO *, REGION **));
  29. static int  __db_e_remfile __P((DB_ENV *));
  30. static int  __db_faultmem __P((void *, size_t, int));
  31. static void __db_region_destroy __P((DB_ENV *, REGINFO *));
  32. /*
  33.  * __db_e_attach
  34.  * Join/create the environment
  35.  *
  36.  * PUBLIC: int __db_e_attach __P((DB_ENV *, u_int32_t *));
  37.  */
  38. int
  39. __db_e_attach(dbenv, init_flagsp)
  40. DB_ENV *dbenv;
  41. u_int32_t *init_flagsp;
  42. {
  43. REGENV *renv;
  44. REGENV_REF ref;
  45. REGINFO *infop;
  46. REGION *rp, tregion;
  47. size_t size;
  48. size_t nrw;
  49. u_int32_t mbytes, bytes;
  50. int retry_cnt, ret, segid;
  51. char buf[sizeof(DB_REGION_FMT) + 20];
  52. #if !defined(HAVE_MUTEX_THREADS)
  53. /*
  54.  * !!!
  55.  * If we don't have spinlocks, we need a file descriptor for fcntl(2)
  56.  * locking.  We use the file handle from the REGENV file for this
  57.  * purpose.
  58.  *
  59.  * Since we may be using shared memory regions, e.g., shmget(2), and
  60.  * not a mapped-in regular file, the backing file may be only a few
  61.  * bytes in length.  So, this depends on the ability to call fcntl to
  62.  * lock file offsets much larger than the actual physical file.  I
  63.  * think that's safe -- besides, very few systems actually need this
  64.  * kind of support, SunOS is the only one still in wide use of which
  65.  * I'm aware.
  66.  *
  67.  * The error case is if an application lacks spinlocks and wants to be
  68.  * threaded.  That doesn't work because fcntl may lock the underlying
  69.  * process, including all its threads.
  70.  */
  71. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  72. __db_err(dbenv,
  73. "architecture lacks fast mutexes: applications cannot be threaded");
  74. return (EINVAL);
  75. }
  76. #endif
  77. /* Initialization */
  78. retry_cnt = 0;
  79. /* Repeated initialization. */
  80. loop: renv = NULL;
  81. /* Set up the DB_ENV's REG_INFO structure. */
  82. if ((ret = __os_calloc(dbenv, 1, sizeof(REGINFO), &infop)) != 0)
  83. return (ret);
  84. infop->type = REGION_TYPE_ENV;
  85. infop->id = REGION_ID_ENV;
  86. infop->mode = dbenv->db_mode;
  87. infop->flags = REGION_JOIN_OK;
  88. if (F_ISSET(dbenv, DB_ENV_CREATE))
  89. F_SET(infop, REGION_CREATE_OK);
  90. /*
  91.  * We have to single-thread the creation of the REGENV region.  Once
  92.  * it exists, we can do locking using locks in the region, but until
  93.  * then we have to be the only player in the game.
  94.  *
  95.  * If this is a private environment, we are only called once and there
  96.  * are no possible race conditions.
  97.  *
  98.  * If this is a public environment, we use the filesystem to ensure
  99.  * the creation of the environment file is single-threaded.
  100.  */
  101. if (F_ISSET(dbenv, DB_ENV_PRIVATE))
  102. goto creation;
  103. /* Build the region name. */
  104. (void)snprintf(buf, sizeof(buf), "%s", DB_REGION_ENV);
  105. if ((ret = __db_appname(dbenv,
  106.     DB_APP_NONE, NULL, buf, 0, NULL, &infop->name)) != 0)
  107. goto err;
  108. /*
  109.  * Try to create the file, if we have the authority.  We have to ensure
  110.  * that multiple threads/processes attempting to simultaneously create
  111.  * the file are properly ordered.  Open using the O_CREAT and O_EXCL
  112.  * flags so that multiple attempts to create the region will return
  113.  * failure in all but one.  POSIX 1003.1 requires that EEXIST be the
  114.  * errno return value -- I sure hope they're right.
  115.  */
  116. if (F_ISSET(dbenv, DB_ENV_CREATE)) {
  117. if ((ret = __os_open(dbenv,
  118.     infop->name, DB_OSO_REGION | DB_OSO_CREATE | DB_OSO_EXCL,
  119.     dbenv->db_mode, dbenv->lockfhp)) == 0)
  120. goto creation;
  121. if (ret != EEXIST) {
  122. __db_err(dbenv,
  123.     "%s: %s", infop->name, db_strerror(ret));
  124. goto err;
  125. }
  126. }
  127. /*
  128.  * If we couldn't create the file, try and open it.  (If that fails,
  129.  * we're done.)
  130.  */
  131. if ((ret = __os_open(dbenv, infop->name,
  132.     DB_OSO_REGION, dbenv->db_mode, dbenv->lockfhp)) != 0)
  133. goto err;
  134. /*
  135.  * !!!
  136.  * The region may be in system memory not backed by the filesystem
  137.  * (more specifically, not backed by this file), and we're joining
  138.  * it.  In that case, the process that created it will have written
  139.  * out a REGENV_REF structure as its only contents.  We read that
  140.  * structure before we do anything further, e.g., we can't just map
  141.  * that file in and then figure out what's going on.
  142.  *
  143.  * All of this noise is because some systems don't have a coherent VM
  144.  * and buffer cache, and what's worse, when you mix operations on the
  145.  * VM and buffer cache, half the time you hang the system.
  146.  *
  147.  * If the file is the size of an REGENV_REF structure, then we know
  148.  * the real region is in some other memory.  (The only way you get a
  149.  * file that size is to deliberately write it, as it's smaller than
  150.  * any possible disk sector created by writing a file or mapping the
  151.  * file into memory.)  In which case, retrieve the structure from the
  152.  * file and use it to acquire the referenced memory.
  153.  *
  154.  * If the structure is larger than a REGENV_REF structure, then this
  155.  * file is backing the shared memory region, and we just map it into
  156.  * memory.
  157.  *
  158.  * And yes, this makes me want to take somebody and kill them.  (I
  159.  * digress -- but you have no freakin' idea.  This is unbelievably
  160.  * stupid and gross, and I've probably spent six months of my life,
  161.  * now, trying to make different versions of it work.)
  162.  */
  163. if ((ret = __os_ioinfo(dbenv, infop->name,
  164.     dbenv->lockfhp, &mbytes, &bytes, NULL)) != 0) {
  165. __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret));
  166. goto err;
  167. }
  168. /*
  169.  * !!!
  170.  * A size_t is OK -- regions get mapped into memory, and so can't
  171.  * be larger than a size_t.
  172.  */
  173. size = mbytes * MEGABYTE + bytes;
  174. /*
  175.  * If the size is less than the size of a REGENV_REF structure, the
  176.  * region (or, possibly, the REGENV_REF structure) has not yet been
  177.  * completely written.  Wait awhile and try again.
  178.  *
  179.  * Otherwise, if the size is the size of a REGENV_REF structure,
  180.  * read it into memory and use it as a reference to the real region.
  181.  */
  182. if (size <= sizeof(ref)) {
  183. if (size != sizeof(ref))
  184. goto retry;
  185. if ((ret = __os_read(dbenv, dbenv->lockfhp, &ref,
  186.     sizeof(ref), &nrw)) != 0 || nrw < (size_t)sizeof(ref)) {
  187. if (ret == 0)
  188. ret = EIO;
  189. __db_err(dbenv,
  190.     "%s: unable to read system-memory information from: %s",
  191.     infop->name, db_strerror(ret));
  192. goto err;
  193. }
  194. size = ref.size;
  195. segid = ref.segid;
  196. F_SET(dbenv, DB_ENV_SYSTEM_MEM);
  197. } else if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) {
  198. ret = EINVAL;
  199. __db_err(dbenv,
  200.     "%s: existing environment not created in system memory: %s",
  201.     infop->name, db_strerror(ret));
  202. goto err;
  203. } else
  204. segid = INVALID_REGION_SEGID;
  205. /*
  206.  * If not doing thread locking, we need to save the file handle for
  207.  * fcntl(2) locking.  Otherwise, discard the handle, we no longer
  208.  * need it, and the less contact between the buffer cache and the VM,
  209.  * the better.
  210.  */
  211. #ifdef HAVE_MUTEX_THREADS
  212.  __os_closehandle(dbenv->lockfhp);
  213. #endif
  214. /* Call the region join routine to acquire the region. */
  215. memset(&tregion, 0, sizeof(tregion));
  216. tregion.size = size;
  217. tregion.segid = segid;
  218. if ((ret = __os_r_attach(dbenv, infop, &tregion)) != 0)
  219. goto err;
  220. /*
  221.  * The environment's REGENV structure has to live at offset 0 instead
  222.  * of the usual shalloc information.  Set the primary reference and
  223.  * correct the "addr" value to reference the shalloc region.  Note,
  224.  * this means that all of our offsets (R_ADDR/R_OFFSET) get shifted
  225.  * as well, but that should be fine.
  226.  */
  227. infop->primary = R_ADDR(infop, 0);
  228. infop->addr = (u_int8_t *)infop->addr + sizeof(REGENV);
  229. /*
  230.  * Check if the environment has had a catastrophic failure.
  231.  *
  232.  * Check the magic number to ensure the region is initialized.  If the
  233.  * magic number isn't set, the lock may not have been initialized, and
  234.  * an attempt to use it could lead to random behavior.
  235.  *
  236.  * The panic and magic values aren't protected by any lock, so we never
  237.  * use them in any check that's more complex than set/not-set.
  238.  *
  239.  * !!!
  240.  * I'd rather play permissions games using the underlying file, but I
  241.  * can't because Windows/NT filesystems won't open files mode 0.
  242.  */
  243. renv = infop->primary;
  244. if (renv->panic) {
  245. ret = __db_panic_msg(dbenv);
  246. goto err;
  247. }
  248. if (renv->magic != DB_REGION_MAGIC)
  249. goto retry;
  250. /* Make sure the region matches our build. */
  251. if (renv->majver != DB_VERSION_MAJOR ||
  252.     renv->minver != DB_VERSION_MINOR ||
  253.     renv->patch != DB_VERSION_PATCH) {
  254. __db_err(dbenv,
  255. "Program version %d.%d.%d doesn't match environment version %d.%d.%d",
  256.     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
  257.     renv->majver, renv->minver, renv->patch);
  258. #ifndef DIAGNOSTIC
  259. ret = EINVAL;
  260. goto err;
  261. #endif
  262. }
  263. /* Lock the environment. */
  264. MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
  265. /*
  266.  * Finally!  We own the environment now.  Repeat the panic check, it's
  267.  * possible that it was set while we waited for the lock.
  268.  */
  269. if (renv->panic) {
  270. ret = __db_panic_msg(dbenv);
  271. goto err_unlock;
  272. }
  273. /*
  274.  * Get a reference to the underlying REGION information for this
  275.  * environment.
  276.  */
  277. if ((ret = __db_des_get(dbenv, infop, infop, &rp)) != 0 || rp == NULL) {
  278. MUTEX_UNLOCK(dbenv, &renv->mutex);
  279. goto find_err;
  280. }
  281. infop->rp = rp;
  282. /*
  283.  * There's still a possibility for inconsistent data.  When we acquired
  284.  * the size of the region and attached to it, it might have still been
  285.  * growing as part of its creation.  We can detect this by checking the
  286.  * size we originally found against the region's current size.  (The
  287.  * region's current size has to be final, the creator finished growing
  288.  * it before releasing the environment for us to lock.)
  289.  */
  290. if (rp->size != size) {
  291. err_unlock: MUTEX_UNLOCK(dbenv, &renv->mutex);
  292. goto retry;
  293. }
  294. /* Increment the reference count. */
  295. ++renv->refcnt;
  296. /*
  297.  * If our caller wants them, return the flags this environment was
  298.  * initialized with.
  299.  */
  300. if (init_flagsp != NULL)
  301. *init_flagsp = renv->init_flags;
  302. /* Discard our lock. */
  303. MUTEX_UNLOCK(dbenv, &renv->mutex);
  304. /*
  305.  * Fault the pages into memory.  Note, do this AFTER releasing the
  306.  * lock, because we're only reading the pages, not writing them.
  307.  */
  308. (void)__db_faultmem(infop->primary, rp->size, 0);
  309. /* Everything looks good, we're done. */
  310. dbenv->reginfo = infop;
  311. return (0);
  312. creation:
  313. /* Create the environment region. */
  314. F_SET(infop, REGION_CREATE);
  315. /*
  316.  * Allocate room for 50 REGION structures plus overhead (we're going
  317.  * to use this space for last-ditch allocation requests), although we
  318.  * should never need anything close to that.
  319.  */
  320. memset(&tregion, 0, sizeof(tregion));
  321. tregion.size = 50 * sizeof(REGION) + 50 * sizeof(MUTEX) + 2048;
  322. tregion.segid = INVALID_REGION_SEGID;
  323. if ((ret = __os_r_attach(dbenv, infop, &tregion)) != 0)
  324. goto err;
  325. /*
  326.  * Fault the pages into memory.  Note, do this BEFORE we initialize
  327.  * anything, because we're writing the pages, not just reading them.
  328.  */
  329. (void)__db_faultmem(infop->addr, tregion.size, 1);
  330. /*
  331.  * The first object in the region is the REGENV structure.  This is
  332.  * different from the other regions, and, from everything else in
  333.  * this region, where all objects are allocated from the pool, i.e.,
  334.  * there aren't any fixed locations.  The remaining space is made
  335.  * available for later allocation.
  336.  *
  337.  * The allocation space must be size_t aligned, because that's what
  338.  * the initialization routine is going to store there.  To make sure
  339.  * that happens, the REGENV structure was padded with a final size_t.
  340.  * No other region needs to worry about it because all of them treat
  341.  * the entire region as allocation space.
  342.  *
  343.  * Set the primary reference and correct the "addr" value to reference
  344.  * the shalloc region.  Note, this requires that we "uncorrect" it at
  345.  * region detach, and that all of our offsets (R_ADDR/R_OFFSET) will be
  346.  * shifted as well, but that should be fine.
  347.  */
  348. infop->primary = R_ADDR(infop, 0);
  349. infop->addr = (u_int8_t *)infop->addr + sizeof(REGENV);
  350. __db_shalloc_init(infop->addr, tregion.size - sizeof(REGENV));
  351. /*
  352.  * Initialize the rest of the REGENV structure, except for the magic
  353.  * number which validates the file/environment.
  354.  */
  355. renv = infop->primary;
  356. renv->panic = 0;
  357. db_version(&renv->majver, &renv->minver, &renv->patch);
  358. SH_LIST_INIT(&renv->regionq);
  359. renv->refcnt = 1;
  360. /*
  361.  * Initialize init_flags to store the flags that any other environment
  362.  * handle that uses DB_JOINENV to join this environment will need.
  363.  */
  364. renv->init_flags = (init_flagsp == NULL) ? 0 : *init_flagsp;
  365. /*
  366.  * Lock the environment.
  367.  *
  368.  * Check the lock call return.  This is the first lock we initialize
  369.  * and acquire, and we have to know if it fails.  (It CAN fail, e.g.,
  370.  * SunOS, when using fcntl(2) for locking and using an in-memory
  371.  * filesystem as the database home.  But you knew that, I'm sure -- it
  372.  * probably wasn't even worth mentioning.)
  373.  */
  374. if ((ret =
  375.     __db_mutex_init(dbenv, &renv->mutex, DB_FCNTL_OFF_GEN, 0)) != 0) {
  376. __db_err(dbenv, "%s: unable to initialize environment lock: %s",
  377.     infop->name, db_strerror(ret));
  378. goto err;
  379. }
  380. if (!F_ISSET(&renv->mutex, MUTEX_IGNORE) &&
  381.     (ret = __db_mutex_lock(dbenv, &renv->mutex, dbenv->lockfhp)) != 0) {
  382. __db_err(dbenv, "%s: unable to acquire environment lock: %s",
  383.     infop->name, db_strerror(ret));
  384. goto err;
  385. }
  386. /*
  387.  * Get the underlying REGION structure for this environment.  Note,
  388.  * we created the underlying OS region before we acquired the REGION
  389.  * structure, which is backwards from the normal procedure.  Update
  390.  * the REGION structure.
  391.  */
  392. if ((ret = __db_des_get(dbenv, infop, infop, &rp)) != 0) {
  393. find_err: __db_err(dbenv,
  394.     "%s: unable to find environment", infop->name);
  395. if (ret == 0)
  396. ret = EINVAL;
  397. goto err;
  398. }
  399. infop->rp = rp;
  400. rp->size = tregion.size;
  401. rp->segid = tregion.segid;
  402. /*
  403.  * !!!
  404.  * If we create an environment where regions are public and in system
  405.  * memory, we have to inform processes joining the environment how to
  406.  * attach to the shared memory segment.  So, we write the shared memory
  407.  * identifier into the file, to be read by those other processes.
  408.  *
  409.  * XXX
  410.  * This is really OS-layer information, but I can't see any easy way
  411.  * to move it down there without passing down information that it has
  412.  * no right to know, e.g., that this is the one-and-only REGENV region
  413.  * and not some other random region.
  414.  */
  415. if (tregion.segid != INVALID_REGION_SEGID) {
  416. ref.size = tregion.size;
  417. ref.segid = tregion.segid;
  418. if ((ret = __os_write(dbenv, dbenv->lockfhp,
  419.     &ref, sizeof(ref), &nrw)) != 0 || nrw != sizeof(ref)) {
  420. __db_err(dbenv,
  421.     "%s: unable to write out public environment ID: %s",
  422.     infop->name, db_strerror(ret));
  423. goto err;
  424. }
  425. }
  426. /*
  427.  * If not doing thread locking, we need to save the file handle for
  428.  * fcntl(2) locking.  Otherwise, discard the handle, we no longer
  429.  * need it, and the less contact between the buffer cache and the VM,
  430.  * the better.
  431.  */
  432. #if defined(HAVE_MUTEX_THREADS)
  433. if (F_ISSET(dbenv->lockfhp, DB_FH_VALID))
  434.  __os_closehandle(dbenv->lockfhp);
  435. #endif
  436. /* Validate the file. */
  437. renv->magic = DB_REGION_MAGIC;
  438. /* Discard our lock. */
  439. MUTEX_UNLOCK(dbenv, &renv->mutex);
  440. /* Everything looks good, we're done. */
  441. dbenv->reginfo = infop;
  442. return (0);
  443. err:
  444. retry: /* Close any open file handle. */
  445. if (F_ISSET(dbenv->lockfhp, DB_FH_VALID))
  446. (void)__os_closehandle(dbenv->lockfhp);
  447. /*
  448.  * If we joined or created the region, detach from it.  If we created
  449.  * it, destroy it.  Note, there's a path in the above code where we're
  450.  * using a temporary REGION structure because we haven't yet allocated
  451.  * the real one.  In that case the region address (addr) will be filled
  452.  * in, but the REGION pointer (rp) won't.  Fix it.
  453.  */
  454. if (infop->addr != NULL) {
  455. if (infop->rp == NULL)
  456. infop->rp = &tregion;
  457. /* Reset the addr value that we "corrected" above. */
  458. infop->addr = infop->primary;
  459. (void)__os_r_detach(dbenv,
  460.     infop, F_ISSET(infop, REGION_CREATE));
  461. }
  462. /* Free the allocated name and/or REGINFO structure. */
  463. if (infop->name != NULL)
  464. __os_freestr(infop->name);
  465. __os_free(infop, sizeof(REGINFO));
  466. /* If we had a temporary error, wait awhile and try again. */
  467. if (ret == 0) {
  468. if (++retry_cnt > 3) {
  469. __db_err(dbenv, "unable to join the environment");
  470. ret = EAGAIN;
  471. } else {
  472. __os_sleep(dbenv, retry_cnt * 3, 0);
  473. goto loop;
  474. }
  475. }
  476. return (ret);
  477. }
  478. /*
  479.  * __db_e_detach --
  480.  * Detach from the environment.
  481.  *
  482.  * PUBLIC: int __db_e_detach __P((DB_ENV *, int));
  483.  */
  484. int
  485. __db_e_detach(dbenv, destroy)
  486. DB_ENV *dbenv;
  487. int destroy;
  488. {
  489. REGENV *renv;
  490. REGINFO *infop;
  491. infop = dbenv->reginfo;
  492. renv = infop->primary;
  493. /* Lock the environment. */
  494. MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
  495. /* Decrement the reference count. */
  496. if (renv->refcnt == 0) {
  497. __db_err(dbenv,
  498.     "region %lu (environment): reference count went negative",
  499.     infop->rp->id);
  500. } else
  501. --renv->refcnt;
  502. /* Release the lock. */
  503. MUTEX_UNLOCK(dbenv, &renv->mutex);
  504. /* Close the locking file handle. */
  505. if (F_ISSET(dbenv->lockfhp, DB_FH_VALID))
  506. (void)__os_closehandle(dbenv->lockfhp);
  507. /* Reset the addr value that we "corrected" above. */
  508. infop->addr = infop->primary;
  509. /*
  510.  * If we are destroying the environment, we need to
  511.  * destroy any system resources backing the mutex.
  512.  * Do that now before we free the memory in __os_r_detach.
  513.  */
  514. if (destroy)
  515. __db_mutex_destroy(&renv->mutex);
  516. /*
  517.  * Release the region, and kill our reference.
  518.  *
  519.  * We set the DBENV->reginfo field to NULL here and discard its memory.
  520.  * DBENV->remove calls __dbenv_remove to do the region remove, and
  521.  * __dbenv_remove attached and then detaches from the region.  We don't
  522.  * want to return to DBENV->remove with a non-NULL DBENV->reginfo field
  523.  * because it will attempt to detach again as part of its cleanup.
  524.  */
  525. (void)__os_r_detach(dbenv, infop, destroy);
  526. if (infop->name != NULL)
  527. __os_free(infop->name, 0);
  528. __os_free(dbenv->reginfo, sizeof(REGINFO));
  529. dbenv->reginfo = NULL;
  530. return (0);
  531. }
  532. /*
  533.  * __db_e_remove --
  534.  * Discard an environment if it's not in use.
  535.  *
  536.  * PUBLIC: int __db_e_remove __P((DB_ENV *, int));
  537.  */
  538. int
  539. __db_e_remove(dbenv, force)
  540. DB_ENV *dbenv;
  541. int force;
  542. {
  543. REGENV *renv;
  544. REGINFO *infop, reginfo;
  545. REGION *rp;
  546. int ret;
  547. /*
  548.  * This routine has to walk a nasty line between not looking into
  549.  * the environment (which may be corrupted after an app or system
  550.  * crash), and removing everything that needs removing.  What we
  551.  * do is:
  552.  * 1. Connect to the environment (so it better be OK).
  553.  * 2. If the environment is in use (reference count is non-zero),
  554.  *    return EBUSY.
  555.  * 3. Overwrite the magic number so that any threads of control
  556.  *    attempting to connect will backoff and retry.
  557.  * 4. Walk the list of regions.  Connect to each region and then
  558.  *    disconnect with the destroy flag set.  This shouldn't cause
  559.  *    any problems, even if the region is corrupted, because we
  560.  *    should never be looking inside the region.
  561.  * 5. Walk the list of files in the directory, unlinking any
  562.  *    files that match a region name.  Unlink the environment
  563.  *    file last.
  564.  *
  565.  * If the force flag is set, we do not acquire any locks during this
  566.  * process.
  567.  */
  568. if (force)
  569. dbenv->db_mutexlocks = 0;
  570. /* Join the environment. */
  571. if ((ret = __db_e_attach(dbenv, NULL)) != 0) {
  572. /*
  573.  * If we can't join it, we assume that's because it doesn't
  574.  * exist.  It would be better to know why we failed, but it
  575.  * probably isn't important.
  576.  */
  577. ret = 0;
  578. if (force)
  579. goto remfiles;
  580. goto err;
  581. }
  582. infop = dbenv->reginfo;
  583. renv = infop->primary;
  584. /* Lock the environment. */
  585. MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
  586. /* If it's in use, we're done. */
  587. if (renv->refcnt == 1 || force) {
  588. /*
  589.  * Set the panic flag and overwrite the magic number.
  590.  *
  591.  * !!!
  592.  * From this point on, there's no going back, we pretty
  593.  * much ignore errors, and just whack on whatever we can.
  594.  */
  595. renv->panic = 1;
  596. renv->magic = 0;
  597. /*
  598.  * Unlock the environment.  We should no longer need the lock
  599.  * because we've poisoned the pool, but we can't continue to
  600.  * hold it either, because other routines may want it.
  601.  */
  602. MUTEX_UNLOCK(dbenv, &renv->mutex);
  603. /*
  604.  * Attach to each sub-region and destroy it.
  605.  *
  606.  * !!!
  607.  * The REGION_CREATE_OK flag is set for Windows/95 -- regions
  608.  * are zero'd out when the last reference to the region goes
  609.  * away, in which case the underlying OS region code requires
  610.  * callers be prepared to create the region in order to join it.
  611.  */
  612. memset(&reginfo, 0, sizeof(reginfo));
  613. restart: for (rp = SH_LIST_FIRST(&renv->regionq, __db_region);
  614.     rp != NULL; rp = SH_LIST_NEXT(rp, q, __db_region)) {
  615. if (rp->type == REGION_TYPE_ENV)
  616. continue;
  617. reginfo.id = rp->id;
  618. reginfo.flags = REGION_CREATE_OK;
  619. if ((ret = __db_r_attach(dbenv, &reginfo, 0)) != 0) {
  620. __db_err(dbenv,
  621.     "region %s attach: %s", db_strerror(ret));
  622. continue;
  623. }
  624. R_UNLOCK(dbenv, &reginfo);
  625. if ((ret = __db_r_detach(dbenv, &reginfo, 1)) != 0) {
  626. __db_err(dbenv,
  627.     "region detach: %s", db_strerror(ret));
  628. continue;
  629. }
  630. /*
  631.  * If we have an error, we continue so we eventually
  632.  * reach the end of the list.  If we succeed, restart
  633.  * the list because it was relinked when we destroyed
  634.  * the entry.
  635.  */
  636. goto restart;
  637. }
  638. /* Destroy the environment's region. */
  639. (void)__db_e_detach(dbenv, 1);
  640. /* Discard the physical files. */
  641. remfiles: (void)__db_e_remfile(dbenv);
  642. } else {
  643. /* Unlock the environment. */
  644. MUTEX_UNLOCK(dbenv, &renv->mutex);
  645. /* Discard the environment. */
  646. (void)__db_e_detach(dbenv, 0);
  647. ret = EBUSY;
  648. }
  649. err:
  650. return (ret);
  651. }
  652. /*
  653.  * __db_e_remfile --
  654.  * Discard any region files in the filesystem.
  655.  */
  656. static int
  657. __db_e_remfile(dbenv)
  658. DB_ENV *dbenv;
  659. {
  660. static char *old_region_names[] = {
  661. "__db_lock.share",
  662. "__db_log.share",
  663. "__db_mpool.share",
  664. "__db_txn.share",
  665. NULL,
  666. };
  667. int cnt, fcnt, lastrm, ret;
  668. u_int8_t saved_byte;
  669. const char *dir;
  670. char *p, **names, *path, buf[sizeof(DB_REGION_FMT) + 20];
  671. /* Get the full path of a file in the environment. */
  672. (void)snprintf(buf, sizeof(buf), "%s", DB_REGION_ENV);
  673. if ((ret =
  674.     __db_appname(dbenv, DB_APP_NONE, NULL, buf, 0, NULL, &path)) != 0)
  675. return (ret);
  676. /* Get the parent directory for the environment. */
  677. if ((p = __db_rpath(path)) == NULL) {
  678. p = path;
  679. saved_byte = *p;
  680. dir = PATH_DOT;
  681. } else {
  682. saved_byte = *p;
  683. *p = '';
  684. dir = path;
  685. }
  686. /* Get the list of file names. */
  687. ret = __os_dirlist(dbenv, dir, &names, &fcnt);
  688. /* Restore the path, and free it. */
  689. *p = saved_byte;
  690. __os_freestr(path);
  691. if (ret != 0) {
  692. __db_err(dbenv, "%s: %s", dir, db_strerror(ret));
  693. return (ret);
  694. }
  695. /*
  696.  * Search for valid region names, and remove them.  We remove the
  697.  * environment region last, because it's the key to this whole mess.
  698.  */
  699. for (lastrm = -1, cnt = fcnt; --cnt >= 0;) {
  700. if (strlen(names[cnt]) != DB_REGION_NAME_LENGTH ||
  701.     memcmp(names[cnt], DB_REGION_FMT, DB_REGION_NAME_NUM) != 0)
  702. continue;
  703. if (strcmp(names[cnt], DB_REGION_ENV) == 0) {
  704. lastrm = cnt;
  705. continue;
  706. }
  707. for (p = names[cnt] + DB_REGION_NAME_NUM;
  708.     *p != '' && isdigit((int)*p); ++p)
  709. ;
  710. if (*p != '')
  711. continue;
  712. if (__db_appname(dbenv,
  713.     DB_APP_NONE, NULL, names[cnt], 0, NULL, &path) == 0) {
  714. (void)__os_unlink(dbenv, path);
  715. __os_freestr(path);
  716. }
  717. }
  718. if (lastrm != -1)
  719. if (__db_appname(dbenv,
  720.     DB_APP_NONE, NULL, names[lastrm], 0, NULL, &path) == 0) {
  721. (void)__os_unlink(dbenv, path);
  722. __os_freestr(path);
  723. }
  724. __os_dirfree(names, fcnt);
  725. /*
  726.  * !!!
  727.  * Backward compatibility -- remove region files from releases
  728.  * before 2.8.XX.
  729.  */
  730. for (names = (char **)old_region_names; *names != NULL; ++names)
  731. if (__db_appname(dbenv,
  732.     DB_APP_NONE, NULL, *names, 0, NULL, &path) == 0) {
  733. (void)__os_unlink(dbenv, path);
  734. __os_freestr(path);
  735. }
  736. return (0);
  737. }
  738. /*
  739.  * __db_e_stat
  740.  * Statistics for the environment.
  741.  *
  742.  * PUBLIC: int __db_e_stat __P((DB_ENV *, REGENV *, REGION *, int *));
  743.  */
  744. int
  745. __db_e_stat(dbenv, arg_renv, arg_regions, arg_regions_cnt)
  746. DB_ENV *dbenv;
  747. REGENV *arg_renv;
  748. REGION *arg_regions;
  749. int *arg_regions_cnt;
  750. {
  751. REGENV *renv;
  752. REGINFO *infop;
  753. REGION *rp;
  754. int n;
  755. infop = dbenv->reginfo;
  756. renv = infop->primary;
  757. rp = infop->rp;
  758. /* Lock the environment. */
  759. MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp);
  760. *arg_renv = *renv;
  761. for (n = 0, rp = SH_LIST_FIRST(&renv->regionq, __db_region);
  762.     n < *arg_regions_cnt && rp != NULL;
  763.     ++n, rp = SH_LIST_NEXT(rp, q, __db_region))
  764. arg_regions[n] = *rp;
  765. /* Release the lock. */
  766. rp = infop->rp;
  767. MUTEX_UNLOCK(dbenv, &rp->mutex);
  768. *arg_regions_cnt = n == 0 ? n : n - 1;
  769. return (0);
  770. }
  771. /*
  772.  * __db_r_attach
  773.  * Join/create a region.
  774.  *
  775.  * PUBLIC: int __db_r_attach __P((DB_ENV *, REGINFO *, size_t));
  776.  */
  777. int
  778. __db_r_attach(dbenv, infop, size)
  779. DB_ENV *dbenv;
  780. REGINFO *infop;
  781. size_t size;
  782. {
  783. REGENV *renv;
  784. REGION *rp;
  785. int ret;
  786. char buf[sizeof(DB_REGION_FMT) + 20];
  787. renv = ((REGINFO *)dbenv->reginfo)->primary;
  788. F_CLR(infop, REGION_CREATE);
  789. /* Lock the environment. */
  790. MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
  791. /* Find or create a REGION structure for this region. */
  792. if ((ret = __db_des_get(dbenv, dbenv->reginfo, infop, &rp)) != 0) {
  793. MUTEX_UNLOCK(dbenv, &renv->mutex);
  794. return (ret);
  795. }
  796. infop->rp = rp;
  797. infop->type = rp->type;
  798. infop->id = rp->id;
  799. /* If we're creating the region, set the desired size. */
  800. if (F_ISSET(infop, REGION_CREATE))
  801. rp->size = size;
  802. /* Join/create the underlying region. */
  803. (void)snprintf(buf, sizeof(buf), DB_REGION_FMT, infop->id);
  804. if ((ret = __db_appname(dbenv,
  805.     DB_APP_NONE, NULL, buf, 0, NULL, &infop->name)) != 0)
  806. goto err;
  807. if ((ret = __os_r_attach(dbenv, infop, rp)) != 0)
  808. goto err;
  809. /*
  810.  * Fault the pages into memory.  Note, do this BEFORE we initialize
  811.  * anything because we're writing pages in created regions, not just
  812.  * reading them.
  813.  */
  814. (void)__db_faultmem(infop->addr,
  815.     rp->size, F_ISSET(infop, REGION_CREATE));
  816. /*
  817.  * !!!
  818.  * The underlying layer may have just decided that we are going
  819.  * to create the region.  There are various system issues that
  820.  * can result in a useless region that requires re-initialization.
  821.  *
  822.  * If we created the region, initialize it for allocation.
  823.  */
  824. if (F_ISSET(infop, REGION_CREATE)) {
  825. ((REGION *)(infop->addr))->magic = DB_REGION_MAGIC;
  826. (void)__db_shalloc_init(infop->addr, rp->size);
  827. }
  828. /*
  829.  * If the underlying REGION isn't the environment, acquire a lock
  830.  * for it and release our lock on the environment.
  831.  */
  832. if (infop->type != REGION_TYPE_ENV) {
  833. MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp);
  834. MUTEX_UNLOCK(dbenv, &renv->mutex);
  835. }
  836. return (0);
  837. /* Discard the underlying region. */
  838. err: if (infop->addr != NULL)
  839. (void)__os_r_detach(dbenv,
  840.     infop, F_ISSET(infop, REGION_CREATE));
  841. infop->rp = NULL;
  842. infop->id = INVALID_REGION_ID;
  843. /* Discard the REGION structure if we created it. */
  844. if (F_ISSET(infop, REGION_CREATE))
  845. (void)__db_des_destroy(dbenv, rp);
  846. /* Release the environment lock. */
  847. MUTEX_UNLOCK(dbenv, &renv->mutex);
  848. return (ret);
  849. }
  850. /*
  851.  * __db_r_detach --
  852.  * Detach from a region.
  853.  *
  854.  * PUBLIC: int __db_r_detach __P((DB_ENV *, REGINFO *, int));
  855.  */
  856. int
  857. __db_r_detach(dbenv, infop, destroy)
  858. DB_ENV *dbenv;
  859. REGINFO *infop;
  860. int destroy;
  861. {
  862. REGENV *renv;
  863. REGION *rp;
  864. int ret, t_ret;
  865. renv = ((REGINFO *)dbenv->reginfo)->primary;
  866. rp = infop->rp;
  867. /* Lock the environment. */
  868. MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
  869. /* Acquire the lock for the REGION. */
  870. MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp);
  871. /*
  872.  * We need to call destroy on per-subsystem info before
  873.  * we free the memory associated with the region.
  874.  */
  875. if (destroy)
  876. __db_region_destroy(dbenv, infop);
  877. /* Detach from the underlying OS region. */
  878. ret = __os_r_detach(dbenv, infop, destroy);
  879. /* Release the REGION lock. */
  880. MUTEX_UNLOCK(dbenv, &rp->mutex);
  881. /* If we destroyed the region, discard the REGION structure. */
  882. if (destroy &&
  883.     ((t_ret = __db_des_destroy(dbenv, rp)) != 0) && ret == 0)
  884. ret = t_ret;
  885. /* Release the environment lock. */
  886. MUTEX_UNLOCK(dbenv, &renv->mutex);
  887. /* Destroy the structure. */
  888. if (infop->name != NULL)
  889. __os_freestr(infop->name);
  890. return (ret);
  891. }
  892. /*
  893.  * __db_des_get --
  894.  * Return a reference to the shared information for a REGION,
  895.  * optionally creating a new entry.
  896.  */
  897. static int
  898. __db_des_get(dbenv, env_infop, infop, rpp)
  899. DB_ENV *dbenv;
  900. REGINFO *env_infop, *infop;
  901. REGION **rpp;
  902. {
  903. REGENV *renv;
  904. REGION *rp, *first_type;
  905. u_int32_t maxid;
  906. int ret;
  907. /*
  908.  * !!!
  909.  * Called with the environment already locked.
  910.  */
  911. *rpp = NULL;
  912. renv = env_infop->primary;
  913. /*
  914.  * If the caller wants to join a region, walk through the existing
  915.  * regions looking for a matching ID (if ID specified) or matching
  916.  * type (if type specified).  If we return based on a matching type
  917.  * return the "primary" region, that is, the first region that was
  918.  * created of this type.
  919.  *
  920.  * Track the maximum region ID so we can allocate a new region,
  921.  * note that we have to start at 1 because the primary environment
  922.  * uses ID == 1.
  923.  */
  924. maxid = REGION_ID_ENV;
  925. for (first_type = NULL,
  926.     rp = SH_LIST_FIRST(&renv->regionq, __db_region);
  927.     rp != NULL; rp = SH_LIST_NEXT(rp, q, __db_region)) {
  928. if (infop->id != INVALID_REGION_ID) {
  929. if (infop->id == rp->id)
  930. break;
  931. continue;
  932. }
  933. if (infop->type == rp->type &&
  934.     F_ISSET(infop, REGION_JOIN_OK) &&
  935.     (first_type == NULL || first_type->id > rp->id))
  936. first_type = rp;
  937. if (rp->id > maxid)
  938. maxid = rp->id;
  939. }
  940. if (rp == NULL)
  941. rp = first_type;
  942. /*
  943.  * If we didn't find a region and we can't create the region, fail.
  944.  * The caller generates any error message.
  945.  */
  946. if (rp == NULL && !F_ISSET(infop, REGION_CREATE_OK))
  947. return (ENOENT);
  948. /*
  949.  * If we didn't find a region, create and initialize a REGION structure
  950.  * for the caller.  If id was set, use that value, otherwise we use the
  951.  * next available ID.
  952.  */
  953. if (rp == NULL) {
  954. if ((ret = __db_shalloc(env_infop->addr,
  955.     sizeof(REGION), MUTEX_ALIGN, &rp)) != 0)
  956. return (ret);
  957. /* Initialize the region. */
  958. memset(rp, 0, sizeof(*rp));
  959. if ((ret = __db_mutex_init(dbenv, &rp->mutex,
  960.     R_OFFSET(env_infop, &rp->mutex) + DB_FCNTL_OFF_GEN,
  961.     0)) != 0) {
  962. __db_shalloc_free(env_infop->addr, rp);
  963. return (ret);
  964. }
  965. rp->segid = INVALID_REGION_SEGID;
  966. /*
  967.  * Set the type and ID; if no region ID was specified,
  968.  * allocate one.
  969.  */
  970. rp->type = infop->type;
  971. rp->id = infop->id == INVALID_REGION_ID ? maxid + 1 : infop->id;
  972. SH_LIST_INSERT_HEAD(&renv->regionq, rp, q, __db_region);
  973. F_SET(infop, REGION_CREATE);
  974. }
  975. *rpp = rp;
  976. return (0);
  977. }
  978. /*
  979.  * __db_des_destroy --
  980.  * Destroy a reference to a REGION.
  981.  */
  982. static int
  983. __db_des_destroy(dbenv, rp)
  984. DB_ENV *dbenv;
  985. REGION *rp;
  986. {
  987. REGINFO *infop;
  988. /*
  989.  * !!!
  990.  * Called with the environment already locked.
  991.  */
  992. infop = dbenv->reginfo;
  993. SH_LIST_REMOVE(rp, q, __db_region);
  994. __db_mutex_destroy(&rp->mutex);
  995. __db_shalloc_free(infop->addr, rp);
  996. return (0);
  997. }
  998. /*
  999.  * __db_faultmem --
  1000.  * Fault the region into memory.
  1001.  */
  1002. static int
  1003. __db_faultmem(addr, size, created)
  1004. void *addr;
  1005. size_t size;
  1006. int created;
  1007. {
  1008. int ret;
  1009. u_int8_t *p, *t;
  1010. /*
  1011.  * It's sometimes significantly faster to page-fault in all of the
  1012.  * region's pages before we run the application, as we see nasty
  1013.  * side-effects when we page-fault while holding various locks, i.e.,
  1014.  * the lock takes a long time to acquire because of the underlying
  1015.  * page fault, and the other threads convoy behind the lock holder.
  1016.  *
  1017.  * If we created the region, we write a non-zero value so that the
  1018.  * system can't cheat.  If we're just joining the region, we can
  1019.  * only read the value and try to confuse the compiler sufficiently
  1020.  * that it doesn't figure out that we're never really using it.
  1021.  */
  1022. ret = 0;
  1023. if (DB_GLOBAL(db_region_init)) {
  1024. if (created)
  1025. for (p = addr, t = (u_int8_t *)addr + size;
  1026.     p < t; p += OS_VMPAGESIZE)
  1027. p[0] = 0xdb;
  1028. else
  1029. for (p = addr, t = (u_int8_t *)addr + size;
  1030.     p < t; p += OS_VMPAGESIZE)
  1031. ret |= p[0];
  1032. }
  1033. return (ret);
  1034. }
  1035. /*
  1036.  * __db_region_destroy --
  1037.  * Destroy per-subsystem region information.
  1038.  * Called with the region already locked.
  1039.  */
  1040. static void
  1041. __db_region_destroy(dbenv, infop)
  1042. DB_ENV *dbenv;
  1043. REGINFO *infop;
  1044. {
  1045. switch (infop->type) {
  1046. case REGION_TYPE_LOCK:
  1047. __lock_region_destroy(dbenv, infop);
  1048. break;
  1049. case REGION_TYPE_MPOOL:
  1050. __mpool_region_destroy(dbenv, infop);
  1051. break;
  1052. case REGION_TYPE_ENV:
  1053. case REGION_TYPE_LOG:
  1054. case REGION_TYPE_MUTEX:
  1055. case REGION_TYPE_TXN:
  1056. break;
  1057. default:
  1058. DB_ASSERT(0);
  1059. break;
  1060. }
  1061. }