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

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_region.c,v 11.49 2002/05/07 18:42:20 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "dbinc/db_shash.h"
  17. #include "dbinc/mp.h"
  18. static int __mpool_init __P((DB_ENV *, DB_MPOOL *, int, int));
  19. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  20. static size_t __mpool_region_maint __P((REGINFO *));
  21. #endif
  22. /*
  23.  * __memp_open --
  24.  * Internal version of memp_open: only called from DB_ENV->open.
  25.  *
  26.  * PUBLIC: int __memp_open __P((DB_ENV *));
  27.  */
  28. int
  29. __memp_open(dbenv)
  30. DB_ENV *dbenv;
  31. {
  32. DB_MPOOL *dbmp;
  33. MPOOL *mp;
  34. REGINFO reginfo;
  35. roff_t reg_size, *regids;
  36. u_int32_t i;
  37. int htab_buckets, ret;
  38. /* Figure out how big each cache region is. */
  39. reg_size = (dbenv->mp_gbytes / dbenv->mp_ncache) * GIGABYTE;
  40. reg_size += ((dbenv->mp_gbytes %
  41.     dbenv->mp_ncache) * GIGABYTE) / dbenv->mp_ncache;
  42. reg_size += dbenv->mp_bytes / dbenv->mp_ncache;
  43. /*
  44.  * Figure out how many hash buckets each region will have.  Assume we
  45.  * want to keep the hash chains with under 10 pages on each chain.  We
  46.  * don't know the pagesize in advance, and it may differ for different
  47.  * files.  Use a pagesize of 1K for the calculation -- we walk these
  48.  * chains a lot, they must be kept short.
  49.  */
  50. htab_buckets = __db_tablesize((reg_size / (1 * 1024)) / 10);
  51. /* Create and initialize the DB_MPOOL structure. */
  52. if ((ret = __os_calloc(dbenv, 1, sizeof(*dbmp), &dbmp)) != 0)
  53. return (ret);
  54. LIST_INIT(&dbmp->dbregq);
  55. TAILQ_INIT(&dbmp->dbmfq);
  56. dbmp->dbenv = dbenv;
  57. /* Join/create the first mpool region. */
  58. memset(&reginfo, 0, sizeof(REGINFO));
  59. reginfo.type = REGION_TYPE_MPOOL;
  60. reginfo.id = INVALID_REGION_ID;
  61. reginfo.mode = dbenv->db_mode;
  62. reginfo.flags = REGION_JOIN_OK;
  63. if (F_ISSET(dbenv, DB_ENV_CREATE))
  64. F_SET(&reginfo, REGION_CREATE_OK);
  65. if ((ret = __db_r_attach(dbenv, &reginfo, reg_size)) != 0)
  66. goto err;
  67. /*
  68.  * If we created the region, initialize it.  Create or join any
  69.  * additional regions.
  70.  */
  71. if (F_ISSET(&reginfo, REGION_CREATE)) {
  72. /*
  73.  * We define how many regions there are going to be, allocate
  74.  * the REGINFO structures and create them.  Make sure we don't
  75.  * clear the wrong entries on error.
  76.  */
  77. dbmp->nreg = dbenv->mp_ncache;
  78. if ((ret = __os_calloc(dbenv,
  79.     dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0)
  80. goto err;
  81. /* Make sure we don't clear the wrong entries on error. */
  82. for (i = 0; i < dbmp->nreg; ++i)
  83. dbmp->reginfo[i].id = INVALID_REGION_ID;
  84. dbmp->reginfo[0] = reginfo;
  85. /* Initialize the first region. */
  86. if ((ret = __mpool_init(dbenv, dbmp, 0, htab_buckets)) != 0)
  87. goto err;
  88. /*
  89.  * Create/initialize remaining regions and copy their IDs into
  90.  * the first region.
  91.  */
  92. mp = R_ADDR(dbmp->reginfo, dbmp->reginfo[0].rp->primary);
  93. regids = R_ADDR(dbmp->reginfo, mp->regids);
  94. for (i = 1; i < dbmp->nreg; ++i) {
  95. dbmp->reginfo[i].type = REGION_TYPE_MPOOL;
  96. dbmp->reginfo[i].id = INVALID_REGION_ID;
  97. dbmp->reginfo[i].mode = dbenv->db_mode;
  98. dbmp->reginfo[i].flags = REGION_CREATE_OK;
  99. if ((ret = __db_r_attach(
  100.     dbenv, &dbmp->reginfo[i], reg_size)) != 0)
  101. goto err;
  102. if ((ret =
  103.     __mpool_init(dbenv, dbmp, i, htab_buckets)) != 0)
  104. goto err;
  105. R_UNLOCK(dbenv, &dbmp->reginfo[i]);
  106. regids[i] = dbmp->reginfo[i].id;
  107. }
  108. R_UNLOCK(dbenv, dbmp->reginfo);
  109. } else {
  110. /*
  111.  * Determine how many regions there are going to be, allocate
  112.  * the REGINFO structures and fill in local copies of that
  113.  * information.
  114.  */
  115. mp = R_ADDR(&reginfo, reginfo.rp->primary);
  116. dbmp->nreg = mp->nreg;
  117. if ((ret = __os_calloc(dbenv,
  118.     dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0)
  119. goto err;
  120. /* Make sure we don't clear the wrong entries on error. */
  121. for (i = 0; i < dbmp->nreg; ++i)
  122. dbmp->reginfo[i].id = INVALID_REGION_ID;
  123. dbmp->reginfo[0] = reginfo;
  124. /*
  125.  * We have to unlock the primary mpool region before we attempt
  126.  * to join the additional mpool regions.  If we don't, we can
  127.  * deadlock.  The scenario is that we hold the primary mpool
  128.  * region lock.  We then try to attach to an additional mpool
  129.  * region, which requires the acquisition/release of the main
  130.  * region lock (to search the list of regions).  If another
  131.  * thread of control already holds the main region lock and is
  132.  * waiting on our primary mpool region lock, we'll deadlock.
  133.  * See [#4696] for more information.
  134.  */
  135. R_UNLOCK(dbenv, dbmp->reginfo);
  136. /* Join remaining regions. */
  137. regids = R_ADDR(dbmp->reginfo, mp->regids);
  138. for (i = 1; i < dbmp->nreg; ++i) {
  139. dbmp->reginfo[i].type = REGION_TYPE_MPOOL;
  140. dbmp->reginfo[i].id = regids[i];
  141. dbmp->reginfo[i].mode = 0;
  142. dbmp->reginfo[i].flags = REGION_JOIN_OK;
  143. if ((ret = __db_r_attach(
  144.     dbenv, &dbmp->reginfo[i], 0)) != 0)
  145. goto err;
  146. R_UNLOCK(dbenv, &dbmp->reginfo[i]);
  147. }
  148. }
  149. /* Set the local addresses for the regions. */
  150. for (i = 0; i < dbmp->nreg; ++i)
  151. dbmp->reginfo[i].primary =
  152.     R_ADDR(&dbmp->reginfo[i], dbmp->reginfo[i].rp->primary);
  153. /* If the region is threaded, allocate a mutex to lock the handles. */
  154. if (F_ISSET(dbenv, DB_ENV_THREAD) &&
  155.     (ret = __db_mutex_setup(dbenv, dbmp->reginfo, &dbmp->mutexp,
  156.     MUTEX_ALLOC | MUTEX_THREAD)) != 0)
  157. goto err;
  158. dbenv->mp_handle = dbmp;
  159. return (0);
  160. err: if (dbmp->reginfo != NULL && dbmp->reginfo[0].addr != NULL) {
  161. if (F_ISSET(dbmp->reginfo, REGION_CREATE))
  162. ret = __db_panic(dbenv, ret);
  163. R_UNLOCK(dbenv, dbmp->reginfo);
  164. for (i = 0; i < dbmp->nreg; ++i)
  165. if (dbmp->reginfo[i].id != INVALID_REGION_ID)
  166. (void)__db_r_detach(
  167.     dbenv, &dbmp->reginfo[i], 0);
  168. __os_free(dbenv, dbmp->reginfo);
  169. }
  170. if (dbmp->mutexp != NULL)
  171. __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp);
  172. __os_free(dbenv, dbmp);
  173. return (ret);
  174. }
  175. /*
  176.  * __mpool_init --
  177.  * Initialize a MPOOL structure in shared memory.
  178.  */
  179. static int
  180. __mpool_init(dbenv, dbmp, reginfo_off, htab_buckets)
  181. DB_ENV *dbenv;
  182. DB_MPOOL *dbmp;
  183. int reginfo_off, htab_buckets;
  184. {
  185. DB_MPOOL_HASH *htab;
  186. MPOOL *mp;
  187. REGINFO *reginfo;
  188. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  189. size_t maint_size;
  190. #endif
  191. int i, ret;
  192. void *p;
  193. mp = NULL;
  194. reginfo = &dbmp->reginfo[reginfo_off];
  195. if ((ret = __db_shalloc(reginfo->addr,
  196.     sizeof(MPOOL), MUTEX_ALIGN, &reginfo->primary)) != 0)
  197. goto mem_err;
  198. reginfo->rp->primary = R_OFFSET(reginfo, reginfo->primary);
  199. mp = reginfo->primary;
  200. memset(mp, 0, sizeof(*mp));
  201. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  202. maint_size = __mpool_region_maint(reginfo);
  203. /* Allocate room for the maintenance info and initialize it. */
  204. if ((ret = __db_shalloc(reginfo->addr,
  205.     sizeof(REGMAINT) + maint_size, 0, &p)) != 0)
  206. goto mem_err;
  207. __db_maintinit(reginfo, p, maint_size);
  208. mp->maint_off = R_OFFSET(reginfo, p);
  209. #endif
  210. if (reginfo_off == 0) {
  211. SH_TAILQ_INIT(&mp->mpfq);
  212. ZERO_LSN(mp->lsn);
  213. mp->nreg = dbmp->nreg;
  214. if ((ret = __db_shalloc(dbmp->reginfo[0].addr,
  215.     dbmp->nreg * sizeof(int), 0, &p)) != 0)
  216. goto mem_err;
  217. mp->regids = R_OFFSET(dbmp->reginfo, p);
  218. }
  219. /* Allocate hash table space and initialize it. */
  220. if ((ret = __db_shalloc(reginfo->addr,
  221.     htab_buckets * sizeof(DB_MPOOL_HASH), 0, &htab)) != 0)
  222. goto mem_err;
  223. mp->htab = R_OFFSET(reginfo, htab);
  224. for (i = 0; i < htab_buckets; i++) {
  225. if ((ret = __db_mutex_setup(dbenv,
  226.     reginfo, &htab[i].hash_mutex,
  227.     MUTEX_NO_RLOCK)) != 0)
  228. return (ret);
  229. SH_TAILQ_INIT(&htab[i].hash_bucket);
  230. htab[i].hash_page_dirty = htab[i].hash_priority = 0;
  231. }
  232. mp->htab_buckets = mp->stat.st_hash_buckets = htab_buckets;
  233. /*
  234.  * Only the environment creator knows the total cache size, fill in
  235.  * those statistics now.
  236.  */
  237. mp->stat.st_gbytes = dbenv->mp_gbytes;
  238. mp->stat.st_bytes = dbenv->mp_bytes;
  239. return (0);
  240. mem_err:__db_err(dbenv, "Unable to allocate memory for mpool region");
  241. return (ret);
  242. }
  243. /*
  244.  * __memp_dbenv_refresh --
  245.  * Clean up after the mpool system on a close or failed open.
  246.  *
  247.  * PUBLIC: int __memp_dbenv_refresh __P((DB_ENV *));
  248.  */
  249. int
  250. __memp_dbenv_refresh(dbenv)
  251. DB_ENV *dbenv;
  252. {
  253. DB_MPOOL *dbmp;
  254. DB_MPOOLFILE *dbmfp;
  255. DB_MPREG *mpreg;
  256. u_int32_t i;
  257. int ret, t_ret;
  258. ret = 0;
  259. dbmp = dbenv->mp_handle;
  260. /* Discard DB_MPREGs. */
  261. while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
  262. LIST_REMOVE(mpreg, q);
  263. __os_free(dbenv, mpreg);
  264. }
  265. /* Discard DB_MPOOLFILEs. */
  266. while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL)
  267. if ((t_ret = __memp_fclose_int(dbmfp, 0)) != 0 && ret == 0)
  268. ret = t_ret;
  269. /* Discard the thread mutex. */
  270. if (dbmp->mutexp != NULL)
  271. __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp);
  272. /* Detach from the region(s). */
  273. for (i = 0; i < dbmp->nreg; ++i)
  274. if ((t_ret = __db_r_detach(
  275.     dbenv, &dbmp->reginfo[i], 0)) != 0 && ret == 0)
  276. ret = t_ret;
  277. __os_free(dbenv, dbmp->reginfo);
  278. __os_free(dbenv, dbmp);
  279. dbenv->mp_handle = NULL;
  280. return (ret);
  281. }
  282. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  283. /*
  284.  * __mpool_region_maint --
  285.  * Return the amount of space needed for region maintenance info.
  286.  *
  287.  */
  288. static size_t
  289. __mpool_region_maint(infop)
  290. REGINFO *infop;
  291. {
  292. size_t s;
  293. int numlocks;
  294. /*
  295.  * For mutex maintenance we need one mutex per possible page.
  296.  * Compute the maximum number of pages this cache can have.
  297.  * Also add in an mpool mutex and mutexes for all dbenv and db
  298.  * handles.
  299.  */
  300. numlocks = ((infop->rp->size / DB_MIN_PGSIZE) + 1);
  301. numlocks += DB_MAX_HANDLES;
  302. s = sizeof(roff_t) * numlocks;
  303. return (s);
  304. }
  305. #endif
  306. /*
  307.  * __mpool_region_destroy
  308.  * Destroy any region maintenance info.
  309.  *
  310.  * PUBLIC: void __mpool_region_destroy __P((DB_ENV *, REGINFO *));
  311.  */
  312. void
  313. __mpool_region_destroy(dbenv, infop)
  314. DB_ENV *dbenv;
  315. REGINFO *infop;
  316. {
  317. __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop,
  318.     ((MPOOL *)R_ADDR(infop, infop->rp->primary))->maint_off));
  319. COMPQUIET(dbenv, NULL);
  320. COMPQUIET(infop, NULL);
  321. }
  322. /*
  323.  * __memp_nameop
  324.  * Remove or rename a file in the pool.
  325.  *
  326.  * PUBLIC: int  __memp_nameop __P((DB_ENV *,
  327.  * PUBLIC:     u_int8_t *, const char *, const char *, const char *));
  328.  *
  329.  * XXX
  330.  * Undocumented interface: DB private.
  331.  */
  332. int
  333. __memp_nameop(dbenv, fileid, newname, fullold, fullnew)
  334. DB_ENV *dbenv;
  335. u_int8_t *fileid;
  336. const char *newname, *fullold, *fullnew;
  337. {
  338. DB_MPOOL *dbmp;
  339. MPOOL *mp;
  340. MPOOLFILE *mfp;
  341. roff_t newname_off;
  342. int locked, ret;
  343. void *p;
  344. locked = 0;
  345. dbmp = NULL;
  346. if (!MPOOL_ON(dbenv))
  347. goto fsop;
  348. dbmp = dbenv->mp_handle;
  349. mp = dbmp->reginfo[0].primary;
  350. /*
  351.  * Remove or rename a file that the mpool might know about.  We assume
  352.  * that the fop layer has the file locked for exclusive access, so we
  353.  * don't worry about locking except for the mpool mutexes.  Checkpoint
  354.  * can happen at any time, independent of file locking, so we have to
  355.  * do the actual unlink or rename system call to avoid any race.
  356.  *
  357.  * If this is a rename, allocate first, because we can't recursively
  358.  * grab the region lock.
  359.  */
  360. if (newname == NULL)
  361. p = NULL;
  362. else {
  363. if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
  364.     NULL, strlen(newname) + 1, &newname_off, &p)) != 0)
  365. return (ret);
  366. memcpy(p, newname, strlen(newname) + 1);
  367. }
  368. locked = 1;
  369. R_LOCK(dbenv, dbmp->reginfo);
  370. /*
  371.  * Find the file -- if mpool doesn't know about this file, that's not
  372.  * an error-- we may not have it open.
  373.  */
  374. for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
  375.     mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
  376. /* Ignore non-active files. */
  377. if (F_ISSET(mfp, MP_DEADFILE | MP_TEMP))
  378. continue;
  379. /* Ignore non-matching files. */
  380. if (memcmp(fileid, R_ADDR(
  381.     dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
  382. continue;
  383. /* If newname is NULL, we're removing the file. */
  384. if (newname == NULL) {
  385. MUTEX_LOCK(dbenv, &mfp->mutex);
  386. MPOOLFILE_IGNORE(mfp);
  387. MUTEX_UNLOCK(dbenv, &mfp->mutex);
  388. } else {
  389. /*
  390.  * Else, it's a rename.  We've allocated memory
  391.  * for the new name.  Swap it with the old one.
  392.  */
  393. p = R_ADDR(dbmp->reginfo, mfp->path_off);
  394. mfp->path_off = newname_off;
  395. }
  396. break;
  397. }
  398. /* Delete the memory we no longer need. */
  399. if (p != NULL)
  400. __db_shalloc_free(dbmp->reginfo[0].addr, p);
  401. fsop: if (newname == NULL)
  402. (void)__os_unlink(dbenv, fullold);
  403. else
  404. (void)__os_rename(dbenv, fullold, fullnew, 1);
  405. if (locked)
  406. R_UNLOCK(dbenv, dbmp->reginfo);
  407. return (0);
  408. }