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

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: lock_region.c,v 11.41 2000/12/20 21:53:04 ubell Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #ifdef HAVE_RPC
  16. #include "db_server.h"
  17. #endif
  18. #include "db_int.h"
  19. #include "db_shash.h"
  20. #include "lock.h"
  21. #ifdef HAVE_RPC
  22. #include "gen_client_ext.h"
  23. #include "rpc_client_ext.h"
  24. #endif
  25. static int  __lock_init __P((DB_ENV *, DB_LOCKTAB *));
  26. static size_t
  27.     __lock_region_size __P((DB_ENV *));
  28. #ifdef MUTEX_SYSTEM_RESOURCES
  29. static size_t __lock_region_maint __P((DB_ENV *));
  30. #endif
  31. /*
  32.  * This conflict array is used for concurrent db access (CDB).  It
  33.  * uses the same locks as the db_rw_conflict array, but adds an IW
  34.  * mode to be used for write cursors.
  35.  */
  36. #define DB_LOCK_CDB_N 5
  37. static u_int8_t const db_cdb_conflicts[] = {
  38. /* N   R   W  WT  IW*/
  39. /*    N */ 0,  0,  0,  0, 0,
  40. /*    R */ 0,  0,  1,  0, 0,
  41. /*    W */ 0,  1,  1,  1, 1,
  42. /*   WT */ 0,  0,  0,  0, 0,
  43. /*   IW */ 0,  0,  1,  0, 1,
  44. };
  45. /*
  46.  * __lock_dbenv_create --
  47.  * Lock specific creation of the DB_ENV structure.
  48.  *
  49.  * PUBLIC: void __lock_dbenv_create __P((DB_ENV *));
  50.  */
  51. void
  52. __lock_dbenv_create(dbenv)
  53. DB_ENV *dbenv;
  54. {
  55. dbenv->lk_max = DB_LOCK_DEFAULT_N;
  56. dbenv->lk_max_lockers = DB_LOCK_DEFAULT_N;
  57. dbenv->lk_max_objects = DB_LOCK_DEFAULT_N;
  58. dbenv->set_lk_conflicts = __lock_set_lk_conflicts;
  59. dbenv->set_lk_detect = __lock_set_lk_detect;
  60. dbenv->set_lk_max = __lock_set_lk_max;
  61. dbenv->set_lk_max_locks = __lock_set_lk_max_locks;
  62. dbenv->set_lk_max_lockers = __lock_set_lk_max_lockers;
  63. dbenv->set_lk_max_objects = __lock_set_lk_max_objects;
  64. #ifdef HAVE_RPC
  65. /*
  66.  * If we have a client, overwrite what we just set up to point
  67.  * to the client functions.
  68.  */
  69. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
  70. dbenv->set_lk_conflicts = __dbcl_set_lk_conflict;
  71. dbenv->set_lk_detect = __dbcl_set_lk_detect;
  72. dbenv->set_lk_max = __dbcl_set_lk_max;
  73. dbenv->set_lk_max_locks = __dbcl_set_lk_max_locks;
  74. dbenv->set_lk_max_lockers = __dbcl_set_lk_max_lockers;
  75. dbenv->set_lk_max_objects = __dbcl_set_lk_max_objects;
  76. }
  77. #endif
  78. }
  79. /*
  80.  * __lock_dbenv_close --
  81.  * Lock specific destruction of the DB_ENV structure.
  82.  *
  83.  * PUBLIC: void __lock_dbenv_close __P((DB_ENV *));
  84.  */
  85. void
  86. __lock_dbenv_close(dbenv)
  87. DB_ENV *dbenv;
  88. {
  89. if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC) && dbenv->lk_conflicts != NULL) {
  90. __os_free(dbenv->lk_conflicts,
  91.     dbenv->lk_modes * dbenv->lk_modes);
  92. dbenv->lk_conflicts = NULL;
  93. }
  94. }
  95. /*
  96.  * __lock_open --
  97.  * Internal version of lock_open: only called from DB_ENV->open.
  98.  *
  99.  * PUBLIC: int __lock_open __P((DB_ENV *));
  100.  */
  101. int
  102. __lock_open(dbenv)
  103. DB_ENV *dbenv;
  104. {
  105. DB_LOCKREGION *region;
  106. DB_LOCKTAB *lt;
  107. size_t size;
  108. int ret;
  109. /* Create the lock table structure. */
  110. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOCKTAB), &lt)) != 0)
  111. return (ret);
  112. lt->dbenv = dbenv;
  113. /* Join/create the lock region. */
  114. lt->reginfo.type = REGION_TYPE_LOCK;
  115. lt->reginfo.id = INVALID_REGION_ID;
  116. lt->reginfo.mode = dbenv->db_mode;
  117. lt->reginfo.flags = REGION_JOIN_OK;
  118. if (F_ISSET(dbenv, DB_ENV_CREATE))
  119. F_SET(&lt->reginfo, REGION_CREATE_OK);
  120. size = __lock_region_size(dbenv);
  121. if ((ret = __db_r_attach(dbenv, &lt->reginfo, size)) != 0)
  122. goto err;
  123. /* If we created the region, initialize it. */
  124. if (F_ISSET(&lt->reginfo, REGION_CREATE))
  125. if ((ret = __lock_init(dbenv, lt)) != 0)
  126. goto err;
  127. /* Set the local addresses. */
  128. region = lt->reginfo.primary =
  129.     R_ADDR(&lt->reginfo, lt->reginfo.rp->primary);
  130. /* Check for incompatible automatic deadlock detection requests. */
  131. if (dbenv->lk_detect != DB_LOCK_NORUN) {
  132. if (region->detect != DB_LOCK_NORUN &&
  133.     dbenv->lk_detect != DB_LOCK_DEFAULT &&
  134.     region->detect != dbenv->lk_detect) {
  135. __db_err(dbenv,
  136.     "lock_open: incompatible deadlock detector mode");
  137. ret = EINVAL;
  138. goto err;
  139. }
  140. /*
  141.  * Upgrade if our caller wants automatic detection, and it
  142.  * was not currently being done, whether or not we created
  143.  * the region.
  144.  */
  145. if (region->detect == DB_LOCK_NORUN)
  146. region->detect = dbenv->lk_detect;
  147. }
  148. /* Set remaining pointers into region. */
  149. lt->conflicts = (u_int8_t *)R_ADDR(&lt->reginfo, region->conf_off);
  150. lt->obj_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->obj_off);
  151. lt->locker_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->locker_off);
  152. R_UNLOCK(dbenv, &lt->reginfo);
  153. dbenv->lk_handle = lt;
  154. return (0);
  155. err: if (lt->reginfo.addr != NULL) {
  156. if (F_ISSET(&lt->reginfo, REGION_CREATE))
  157. ret = __db_panic(dbenv, ret);
  158. R_UNLOCK(dbenv, &lt->reginfo);
  159. (void)__db_r_detach(dbenv, &lt->reginfo, 0);
  160. }
  161. __os_free(lt, sizeof(*lt));
  162. return (ret);
  163. }
  164. /*
  165.  * __lock_init --
  166.  * Initialize the lock region.
  167.  */
  168. static int
  169. __lock_init(dbenv, lt)
  170. DB_ENV *dbenv;
  171. DB_LOCKTAB *lt;
  172. {
  173. const u_int8_t *lk_conflicts;
  174. struct __db_lock *lp;
  175. DB_LOCKER *lidp;
  176. DB_LOCKOBJ *op;
  177. DB_LOCKREGION *region;
  178. #ifdef MUTEX_SYSTEM_RESOURCES
  179. size_t maint_size;
  180. #endif
  181. u_int32_t i, lk_modes;
  182. u_int8_t *addr;
  183. int ret;
  184. if ((ret = __db_shalloc(lt->reginfo.addr,
  185.     sizeof(DB_LOCKREGION), 0, &lt->reginfo.primary)) != 0)
  186. goto mem_err;
  187. lt->reginfo.rp->primary = R_OFFSET(&lt->reginfo, lt->reginfo.primary);
  188. region = lt->reginfo.primary;
  189. memset(region, 0, sizeof(*region));
  190. /* Select a conflict matrix if none specified. */
  191. if (dbenv->lk_modes == 0)
  192. if (CDB_LOCKING(dbenv)) {
  193. lk_modes = DB_LOCK_CDB_N;
  194. lk_conflicts = db_cdb_conflicts;
  195. } else {
  196. lk_modes = DB_LOCK_RIW_N;
  197. lk_conflicts = db_riw_conflicts;
  198. }
  199. else {
  200. lk_modes = dbenv->lk_modes;
  201. lk_conflicts = dbenv->lk_conflicts;
  202. }
  203. region->id = 0;
  204. region->need_dd = 0;
  205. region->detect = DB_LOCK_NORUN;
  206. region->maxlocks = dbenv->lk_max;
  207. region->maxlockers = dbenv->lk_max_lockers;
  208. region->maxobjects = dbenv->lk_max_objects;
  209. region->locker_t_size = __db_tablesize(dbenv->lk_max_lockers);
  210. region->object_t_size = __db_tablesize(dbenv->lk_max_objects);
  211. region->nmodes = lk_modes;
  212. region->nlocks = 0;
  213. region->maxnlocks = 0;
  214. region->nlockers = 0;
  215. region->maxnlockers = 0;
  216. region->nobjects = 0;
  217. region->maxnobjects = 0;
  218. region->nconflicts = 0;
  219. region->nrequests = 0;
  220. region->nreleases = 0;
  221. region->ndeadlocks = 0;
  222. /* Allocate room for the conflict matrix and initialize it. */
  223. if ((ret =
  224.     __db_shalloc(lt->reginfo.addr, lk_modes * lk_modes, 0, &addr)) != 0)
  225. goto mem_err;
  226. memcpy(addr, lk_conflicts, lk_modes * lk_modes);
  227. region->conf_off = R_OFFSET(&lt->reginfo, addr);
  228. /* Allocate room for the object hash table and initialize it. */
  229. if ((ret = __db_shalloc(lt->reginfo.addr,
  230.     region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
  231. goto mem_err;
  232. __db_hashinit(addr, region->object_t_size);
  233. region->obj_off = R_OFFSET(&lt->reginfo, addr);
  234. /* Allocate room for the locker hash table and initialize it. */
  235. if ((ret = __db_shalloc(lt->reginfo.addr,
  236.     region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
  237. goto mem_err;
  238. __db_hashinit(addr, region->locker_t_size);
  239. region->locker_off = R_OFFSET(&lt->reginfo, addr);
  240. #ifdef MUTEX_SYSTEM_RESOURCES
  241. maint_size = __lock_region_maint(dbenv);
  242. /* Allocate room for the locker maintenance info and initialize it. */
  243. if ((ret = __db_shalloc(lt->reginfo.addr,
  244.     sizeof(REGMAINT) + maint_size, 0, &addr)) != 0)
  245. goto mem_err;
  246. __db_maintinit(&lt->reginfo, addr, maint_size);
  247. region->maint_off = R_OFFSET(&lt->reginfo, addr);
  248. #endif
  249. /*
  250.  * Initialize locks onto a free list. Initialize and lock the mutex
  251.  * so that when we need to block, all we need do is try to acquire
  252.  * the mutex.
  253.  */
  254. SH_TAILQ_INIT(&region->free_locks);
  255. for (i = 0; i < region->maxlocks; ++i) {
  256. if ((ret = __db_shalloc(lt->reginfo.addr,
  257.     sizeof(struct __db_lock), MUTEX_ALIGN, &lp)) != 0)
  258. goto mem_err;
  259. lp->status = DB_LSTAT_FREE;
  260. if ((ret = __db_shmutex_init(dbenv, &lp->mutex,
  261.     R_OFFSET(&lt->reginfo, &lp->mutex) + DB_FCNTL_OFF_LOCK,
  262.     MUTEX_SELF_BLOCK, &lt->reginfo,
  263.     (REGMAINT *)R_ADDR(&lt->reginfo, region->maint_off))) != 0)
  264. return (ret);
  265. MUTEX_LOCK(dbenv, &lp->mutex, lt->dbenv->lockfhp);
  266. SH_TAILQ_INSERT_HEAD(&region->free_locks, lp, links, __db_lock);
  267. }
  268. /* Initialize objects onto a free list.  */
  269. SH_TAILQ_INIT(&region->dd_objs);
  270. SH_TAILQ_INIT(&region->free_objs);
  271. for (i = 0; i < region->maxobjects; ++i) {
  272. if ((ret = __db_shalloc(lt->reginfo.addr,
  273.     sizeof(DB_LOCKOBJ), 0, &op)) != 0)
  274. goto mem_err;
  275. SH_TAILQ_INSERT_HEAD(
  276.     &region->free_objs, op, links, __db_lockobj);
  277. }
  278. /* Initialize lockers onto a free list.  */
  279. SH_TAILQ_INIT(&region->free_lockers);
  280. for (i = 0; i < region->maxlockers; ++i) {
  281. if ((ret = __db_shalloc(lt->reginfo.addr,
  282.     sizeof(DB_LOCKER), 0, &lidp)) != 0) {
  283. mem_err: __db_err(dbenv, "Unable to allocate memory for the lock table");
  284. return (ret);
  285. }
  286. SH_TAILQ_INSERT_HEAD(
  287.     &region->free_lockers, lidp, links, __db_locker);
  288. }
  289. return (0);
  290. }
  291. /*
  292.  * __lock_close --
  293.  * Internal version of lock_close: only called from db_appinit.
  294.  *
  295.  * PUBLIC: int __lock_close __P((DB_ENV *));
  296.  */
  297. int
  298. __lock_close(dbenv)
  299. DB_ENV *dbenv;
  300. {
  301. DB_LOCKTAB *lt;
  302. int ret;
  303. lt = dbenv->lk_handle;
  304. /* Detach from the region. */
  305. ret = __db_r_detach(dbenv, &lt->reginfo, 0);
  306. __os_free(lt, sizeof(*lt));
  307. dbenv->lk_handle = NULL;
  308. return (ret);
  309. }
  310. /*
  311.  * __lock_region_size --
  312.  * Return the region size.
  313.  */
  314. static size_t
  315. __lock_region_size(dbenv)
  316. DB_ENV *dbenv;
  317. {
  318. size_t retval;
  319. /*
  320.  * Figure out how much space we're going to need.  This list should
  321.  * map one-to-one with the __db_shalloc calls in __lock_init.
  322.  */
  323. retval = 0;
  324. retval += __db_shalloc_size(sizeof(DB_LOCKREGION), 1);
  325. retval += __db_shalloc_size(dbenv->lk_modes * dbenv->lk_modes, 1);
  326. retval += __db_shalloc_size(
  327.      __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)), 1);
  328. retval += __db_shalloc_size(
  329.      __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)), 1);
  330. #ifdef MUTEX_SYSTEM_RESOURCES
  331. retval +=
  332.     __db_shalloc_size(sizeof(REGMAINT) + __lock_region_maint(dbenv), 1);
  333. #endif
  334. retval += __db_shalloc_size(
  335.      sizeof(struct __db_lock), MUTEX_ALIGN) * dbenv->lk_max;
  336. retval += __db_shalloc_size(sizeof(DB_LOCKOBJ), 1) * dbenv->lk_max_objects;
  337. retval += __db_shalloc_size(sizeof(DB_LOCKER), 1) * dbenv->lk_max_lockers;
  338. /*
  339.  * Include 16 bytes of string space per lock.  DB doesn't use it
  340.  * because we pre-allocate lock space for DBTs in the structure.
  341.  */
  342. retval += __db_shalloc_size(dbenv->lk_max * 16, sizeof(size_t));
  343. /* And we keep getting this wrong, let's be generous. */
  344. retval += retval / 4;
  345. return (retval);
  346. }
  347. #ifdef MUTEX_SYSTEM_RESOURCES
  348. /*
  349.  * __lock_region_maint --
  350.  * Return the amount of space needed for region maintenance info.
  351.  */
  352. static size_t
  353. __lock_region_maint(dbenv)
  354. DB_ENV *dbenv;
  355. {
  356. size_t s;
  357. s = sizeof(MUTEX *) * dbenv->lk_max;
  358. return (s);
  359. }
  360. #endif
  361. /*
  362.  * __lock_region_destroy
  363.  * Destroy any region maintenance info.
  364.  *
  365.  * PUBLIC: void __lock_region_destroy __P((DB_ENV *, REGINFO *));
  366.  */
  367. void
  368. __lock_region_destroy(dbenv, infop)
  369. DB_ENV *dbenv;
  370. REGINFO *infop;
  371. {
  372. DB_LOCKREGION *region;
  373. COMPQUIET(dbenv, NULL);
  374. region = R_ADDR(infop, infop->rp->primary);
  375. __db_shlocks_destroy(infop,
  376.     (REGMAINT *)R_ADDR(infop, region->maint_off));
  377. return;
  378. }