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

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