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

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_deadlock.c,v 11.23 2000/12/08 20:15:31 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. #include "txn.h"
  22. #ifdef HAVE_RPC
  23. #include "gen_client_ext.h"
  24. #include "rpc_client_ext.h"
  25. #endif
  26. #define ISSET_MAP(M, N) ((M)[(N) / 32] & (1 << (N) % 32))
  27. #define CLEAR_MAP(M, N) {
  28. u_int32_t __i;
  29. for (__i = 0; __i < (N); __i++)
  30. (M)[__i] = 0;
  31. }
  32. #define SET_MAP(M, B) ((M)[(B) / 32] |= (1 << ((B) % 32)))
  33. #define CLR_MAP(M, B) ((M)[(B) / 32] &= ~(1 << ((B) % 32)))
  34. #define OR_MAP(D, S, N) {
  35. u_int32_t __i;
  36. for (__i = 0; __i < (N); __i++)
  37. D[__i] |= S[__i];
  38. }
  39. #define BAD_KILLID 0xffffffff
  40. typedef struct {
  41. int valid;
  42. u_int32_t id;
  43. u_int32_t last_lock;
  44. u_int32_t last_locker_id;
  45. db_pgno_t pgno;
  46. } locker_info;
  47. static int  __dd_abort __P((DB_ENV *, locker_info *));
  48. static int  __dd_build
  49. __P((DB_ENV *, u_int32_t **, u_int32_t *, locker_info **));
  50. static int  __dd_find
  51. __P((DB_ENV *,u_int32_t *, locker_info *, u_int32_t, u_int32_t ***));
  52. #ifdef DIAGNOSTIC
  53. static void __dd_debug __P((DB_ENV *, locker_info *, u_int32_t *, u_int32_t));
  54. #endif
  55. int
  56. lock_detect(dbenv, flags, atype, abortp)
  57. DB_ENV *dbenv;
  58. u_int32_t flags, atype;
  59. int *abortp;
  60. {
  61. DB_LOCKREGION *region;
  62. DB_LOCKTAB *lt;
  63. locker_info *idmap;
  64. u_int32_t *bitmap, **deadp, **free_me, i, killid, nentries, nlockers;
  65. int do_pass, ret;
  66. #ifdef HAVE_RPC
  67. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  68. return (__dbcl_lock_detect(dbenv, flags, atype, abortp));
  69. #endif
  70. PANIC_CHECK(dbenv);
  71. ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK);
  72. lt = dbenv->lk_handle;
  73. if (abortp != NULL)
  74. *abortp = 0;
  75. /* Validate arguments. */
  76. if ((ret =
  77.     __db_fchk(dbenv, "lock_detect", flags, DB_LOCK_CONFLICT)) != 0)
  78. return (ret);
  79. /* Check if a detector run is necessary. */
  80. LOCKREGION(dbenv, lt);
  81. if (LF_ISSET(DB_LOCK_CONFLICT)) {
  82. /* Make a pass every time a lock waits. */
  83. region = lt->reginfo.primary;
  84. do_pass = region->need_dd != 0;
  85. if (!do_pass) {
  86. UNLOCKREGION(dbenv, lt);
  87. return (0);
  88. }
  89. }
  90. /* Build the waits-for bitmap. */
  91. ret = __dd_build(dbenv, &bitmap, &nlockers, &idmap);
  92. UNLOCKREGION(dbenv, lt);
  93. if (ret != 0)
  94. return (ret);
  95. if (nlockers == 0)
  96. return (0);
  97. #ifdef DIAGNOSTIC
  98. if (FLD_ISSET(dbenv->verbose, DB_VERB_WAITSFOR))
  99. __dd_debug(dbenv, idmap, bitmap, nlockers);
  100. #endif
  101. /* Find a deadlock. */
  102. if ((ret = __dd_find(dbenv, bitmap, idmap, nlockers, &deadp)) != 0)
  103. return (ret);
  104. nentries = ALIGN(nlockers, 32) / 32;
  105. killid = BAD_KILLID;
  106. free_me = deadp;
  107. for (; *deadp != NULL; deadp++) {
  108. if (abortp != NULL)
  109. ++*abortp;
  110. switch (atype) { /* Kill someone. */
  111. case DB_LOCK_OLDEST:
  112. /*
  113.  * Find the first bit set in the current
  114.  * array and then look for a lower tid in
  115.  * the array.
  116.  */
  117. for (i = 0; i < nlockers; i++)
  118. if (ISSET_MAP(*deadp, i)) {
  119. killid = i;
  120. break;
  121. }
  122. /*
  123.  * It's conceivable that under XA, the locker could
  124.  * have gone away.
  125.  */
  126. if (killid == BAD_KILLID)
  127. break;
  128. /*
  129.  * The oldest transaction has the lowest
  130.  * transaction id.
  131.  */
  132. for (i = killid + 1; i < nlockers; i++)
  133. if (ISSET_MAP(*deadp, i) &&
  134.     idmap[i].id < idmap[killid].id)
  135. killid = i;
  136. break;
  137. case DB_LOCK_DEFAULT:
  138. case DB_LOCK_RANDOM:
  139. /*
  140.  * We are trying to calculate the id of the
  141.  * locker whose entry is indicated by deadlock.
  142.  */
  143. killid = (*deadp - bitmap) / nentries;
  144. break;
  145. case DB_LOCK_YOUNGEST:
  146. /*
  147.  * Find the first bit set in the current
  148.  * array and then look for a lower tid in
  149.  * the array.
  150.  */
  151. for (i = 0; i < nlockers; i++)
  152. if (ISSET_MAP(*deadp, i)) {
  153. killid = i;
  154. break;
  155. }
  156. /*
  157.  * It's conceivable that under XA, the locker could
  158.  * have gone away.
  159.  */
  160. if (killid == BAD_KILLID)
  161. break;
  162. /*
  163.  * The youngest transaction has the highest
  164.  * transaction id.
  165.  */
  166. for (i = killid + 1; i < nlockers; i++)
  167. if (ISSET_MAP(*deadp, i) &&
  168.     idmap[i].id > idmap[killid].id)
  169. killid = i;
  170. break;
  171. default:
  172. killid = BAD_KILLID;
  173. ret = EINVAL;
  174. }
  175. if (killid == BAD_KILLID)
  176. continue;
  177. /* Kill the locker with lockid idmap[killid]. */
  178. if ((ret = __dd_abort(dbenv, &idmap[killid])) != 0) {
  179. /*
  180.  * It's possible that the lock was already aborted;
  181.  * this isn't necessarily a problem, so do not treat
  182.  * it as an error.
  183.  */
  184. if (ret == DB_ALREADY_ABORTED)
  185. ret = 0;
  186. else
  187. __db_err(dbenv,
  188.     "warning: unable to abort locker %lx",
  189.     (u_long)idmap[killid].id);
  190. } else if (FLD_ISSET(dbenv->verbose, DB_VERB_DEADLOCK))
  191. __db_err(dbenv,
  192.     "Aborting locker %lx", (u_long)idmap[killid].id);
  193. }
  194. __os_free(free_me, 0);
  195. __os_free(bitmap, 0);
  196. __os_free(idmap, 0);
  197. return (ret);
  198. }
  199. /*
  200.  * ========================================================================
  201.  * Utilities
  202.  */
  203. # define DD_INVALID_ID ((u_int32_t) -1)
  204. static int
  205. __dd_build(dbenv, bmp, nlockers, idmap)
  206. DB_ENV *dbenv;
  207. u_int32_t **bmp, *nlockers;
  208. locker_info **idmap;
  209. {
  210. struct __db_lock *lp;
  211. DB_LOCKER *lip, *lockerp, *child;
  212. DB_LOCKOBJ *op, *lo;
  213. DB_LOCKREGION *region;
  214. DB_LOCKTAB *lt;
  215. locker_info *id_array;
  216. u_int32_t *bitmap, count, dd, *entryp, i, id, ndx, nentries, *tmpmap;
  217. u_int8_t *pptr;
  218. int is_first, ret;
  219. lt = dbenv->lk_handle;
  220. region = lt->reginfo.primary;
  221. /*
  222.  * We'll check how many lockers there are, add a few more in for
  223.  * good measure and then allocate all the structures.  Then we'll
  224.  * verify that we have enough room when we go back in and get the
  225.  * mutex the second time.
  226.  */
  227. retry: count = region->nlockers;
  228. region->need_dd = 0;
  229. if (count == 0) {
  230. *nlockers = 0;
  231. return (0);
  232. }
  233. if (FLD_ISSET(dbenv->verbose, DB_VERB_DEADLOCK))
  234. __db_err(dbenv, "%lu lockers", (u_long)count);
  235. count += 40;
  236. nentries = ALIGN(count, 32) / 32;
  237. /*
  238.  * Allocate enough space for a count by count bitmap matrix.
  239.  *
  240.  * XXX
  241.  * We can probably save the malloc's between iterations just
  242.  * reallocing if necessary because count grew by too much.
  243.  */
  244. if ((ret = __os_calloc(dbenv, (size_t)count,
  245.     sizeof(u_int32_t) * nentries, &bitmap)) != 0)
  246. return (ret);
  247. if ((ret = __os_calloc(dbenv,
  248.     sizeof(u_int32_t), nentries, &tmpmap)) != 0) {
  249. __os_free(bitmap, sizeof(u_int32_t) * nentries);
  250. return (ret);
  251. }
  252. if ((ret = __os_calloc(dbenv,
  253.     (size_t)count, sizeof(locker_info), &id_array)) != 0) {
  254. __os_free(bitmap, count * sizeof(u_int32_t) * nentries);
  255. __os_free(tmpmap, sizeof(u_int32_t) * nentries);
  256. return (ret);
  257. }
  258. /*
  259.  * Now go back in and actually fill in the matrix.
  260.  */
  261. if (region->nlockers > count) {
  262. __os_free(bitmap, count * sizeof(u_int32_t) * nentries);
  263. __os_free(tmpmap, sizeof(u_int32_t) * nentries);
  264. __os_free(id_array, count * sizeof(locker_info));
  265. goto retry;
  266. }
  267. /*
  268.  * First we go through and assign each locker a deadlock detector id.
  269.  */
  270. for (id = 0, i = 0; i < region->locker_t_size; i++) {
  271. for (lip = SH_TAILQ_FIRST(&lt->locker_tab[i], __db_locker);
  272.     lip != NULL; lip = SH_TAILQ_NEXT(lip, links, __db_locker))
  273. if (lip->master_locker == INVALID_ROFF) {
  274. lip->dd_id = id++;
  275. id_array[lip->dd_id].id = lip->id;
  276. } else
  277. lip->dd_id = DD_INVALID_ID;
  278. }
  279. /*
  280.  * We only need consider objects that have waiters, so we use
  281.  * the list of objects with waiters (dd_objs) instead of traversing
  282.  * the entire hash table.  For each object, we traverse the waiters
  283.  * list and add an entry in the waitsfor matrix for each waiter/holder
  284.  * combination.
  285.  */
  286. for (op = SH_TAILQ_FIRST(&region->dd_objs, __db_lockobj);
  287.     op != NULL; op = SH_TAILQ_NEXT(op, dd_links, __db_lockobj)) {
  288. CLEAR_MAP(tmpmap, nentries);
  289. /*
  290.  * First we go through and create a bit map that
  291.  * represents all the holders of this object.
  292.  */
  293. for (lp = SH_TAILQ_FIRST(&op->holders, __db_lock);
  294.     lp != NULL;
  295.     lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
  296. LOCKER_LOCK(lt, region, lp->holder, ndx);
  297. if ((ret = __lock_getlocker(lt,
  298.     lp->holder, ndx, 0, &lockerp)) != 0)
  299. continue;
  300. if (lockerp->dd_id == DD_INVALID_ID)
  301. dd = ((DB_LOCKER *)
  302.      R_ADDR(&lt->reginfo,
  303.      lockerp->master_locker))->dd_id;
  304. else
  305. dd = lockerp->dd_id;
  306. id_array[dd].valid = 1;
  307. /*
  308.  * If the holder has already been aborted, then
  309.  * we should ignore it for now.
  310.  */
  311. if (lp->status == DB_LSTAT_HELD)
  312. SET_MAP(tmpmap, dd);
  313. }
  314. /*
  315.  * Next, for each waiter, we set its row in the matrix
  316.  * equal to the map of holders we set up above.
  317.  */
  318. for (is_first = 1,
  319.     lp = SH_TAILQ_FIRST(&op->waiters, __db_lock);
  320.     lp != NULL;
  321.     is_first = 0,
  322.     lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
  323. LOCKER_LOCK(lt, region, lp->holder, ndx);
  324. if ((ret = __lock_getlocker(lt,
  325.     lp->holder, ndx, 0, &lockerp)) != 0)
  326. continue;
  327. if (lockerp->dd_id == DD_INVALID_ID)
  328. dd = ((DB_LOCKER *)
  329.      R_ADDR(&lt->reginfo,
  330.      lockerp->master_locker))->dd_id;
  331. else
  332. dd = lockerp->dd_id;
  333. id_array[dd].valid = 1;
  334. /*
  335.  * If the transaction is pending abortion, then
  336.  * ignore it on this iteration.
  337.  */
  338. if (lp->status != DB_LSTAT_WAITING)
  339. continue;
  340. entryp = bitmap + (nentries * dd);
  341. OR_MAP(entryp, tmpmap, nentries);
  342. /*
  343.  * If this is the first waiter on the queue,
  344.  * then we remove the waitsfor relationship
  345.  * with oneself.  However, if it's anywhere
  346.  * else on the queue, then we have to keep
  347.  * it and we have an automatic deadlock.
  348.  */
  349. if (is_first)
  350. CLR_MAP(entryp, dd);
  351. }
  352. }
  353. /* Now for each locker; record its last lock. */
  354. for (id = 0; id < count; id++) {
  355. if (!id_array[id].valid)
  356. continue;
  357. LOCKER_LOCK(lt, region, id_array[id].id, ndx);
  358. if ((ret = __lock_getlocker(lt,
  359.     id_array[id].id, ndx, 0, &lockerp)) != 0) {
  360. __db_err(dbenv,
  361.     "No locks for locker %lu", (u_long)id_array[id].id);
  362. continue;
  363. }
  364. /*
  365.  * If this is a master transaction, try to
  366.  * find one of its children's locks first,
  367.  * as they are probably more recent.
  368.  */
  369. child = SH_LIST_FIRST(&lockerp->child_locker, __db_locker);
  370. if (child != NULL) {
  371. do {
  372. lp = SH_LIST_FIRST(&child->heldby, __db_lock);
  373. if (lp != NULL &&
  374.      lp->status == DB_LSTAT_WAITING) {
  375. id_array[id].last_locker_id = child->id;
  376. goto get_lock;
  377. }
  378. child = SH_LIST_NEXT(
  379.     child, child_link, __db_locker);
  380. } while (child != NULL);
  381. }
  382. lp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
  383. if (lp != NULL) {
  384. id_array[id].last_locker_id = lockerp->id;
  385. get_lock: id_array[id].last_lock = R_OFFSET(&lt->reginfo, lp);
  386. lo = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
  387. pptr = SH_DBT_PTR(&lo->lockobj);
  388. if (lo->lockobj.size >= sizeof(db_pgno_t))
  389. memcpy(&id_array[id].pgno,
  390.     pptr, sizeof(db_pgno_t));
  391. else
  392. id_array[id].pgno = 0;
  393. }
  394. }
  395. /* Pass complete, reset the deadlock detector bit. */
  396. region->need_dd = 0;
  397. /*
  398.  * Now we can release everything except the bitmap matrix that we
  399.  * created.
  400.  */
  401. *nlockers = id;
  402. *idmap = id_array;
  403. *bmp = bitmap;
  404. __os_free(tmpmap, sizeof(u_int32_t) * nentries);
  405. return (0);
  406. }
  407. static int
  408. __dd_find(dbenv, bmp, idmap, nlockers, deadp)
  409. DB_ENV *dbenv;
  410. u_int32_t *bmp, nlockers;
  411. locker_info *idmap;
  412. u_int32_t ***deadp;
  413. {
  414. u_int32_t i, j, k, nentries, *mymap, *tmpmap;
  415. u_int32_t **retp;
  416. int ndead, ndeadalloc, ret;
  417. #undef INITIAL_DEAD_ALLOC
  418. #define INITIAL_DEAD_ALLOC 8
  419. ndeadalloc = INITIAL_DEAD_ALLOC;
  420. ndead = 0;
  421. if ((ret = __os_malloc(dbenv,
  422.     ndeadalloc * sizeof(u_int32_t *), NULL, &retp)) != 0)
  423. return (ret);
  424. /*
  425.  * For each locker, OR in the bits from the lockers on which that
  426.  * locker is waiting.
  427.  */
  428. nentries = ALIGN(nlockers, 32) / 32;
  429. for (mymap = bmp, i = 0; i < nlockers; i++, mymap += nentries) {
  430. if (!idmap[i].valid)
  431. continue;
  432. for (j = 0; j < nlockers; j++) {
  433. if (!ISSET_MAP(mymap, j))
  434. continue;
  435. /* Find the map for this bit. */
  436. tmpmap = bmp + (nentries * j);
  437. OR_MAP(mymap, tmpmap, nentries);
  438. if (!ISSET_MAP(mymap, i))
  439. continue;
  440. /* Make sure we leave room for NULL. */
  441. if (ndead + 2 >= ndeadalloc) {
  442. ndeadalloc <<= 1;
  443. /*
  444.  * If the alloc fails, then simply return the
  445.  * deadlocks that we already have.
  446.  */
  447. if (__os_realloc(dbenv,
  448.     ndeadalloc * sizeof(u_int32_t),
  449.     NULL, &retp) != 0) {
  450. retp[ndead] = NULL;
  451. *deadp = retp;
  452. return (0);
  453. }
  454. }
  455. retp[ndead++] = mymap;
  456. /* Mark all participants in this deadlock invalid. */
  457. for (k = 0; k < nlockers; k++)
  458. if (ISSET_MAP(mymap, k))
  459. idmap[k].valid = 0;
  460. break;
  461. }
  462. }
  463. retp[ndead] = NULL;
  464. *deadp = retp;
  465. return (0);
  466. }
  467. static int
  468. __dd_abort(dbenv, info)
  469. DB_ENV *dbenv;
  470. locker_info *info;
  471. {
  472. struct __db_lock *lockp;
  473. DB_LOCKER *lockerp;
  474. DB_LOCKOBJ *sh_obj;
  475. DB_LOCKREGION *region;
  476. DB_LOCKTAB *lt;
  477. u_int32_t ndx;
  478. int ret;
  479. lt = dbenv->lk_handle;
  480. region = lt->reginfo.primary;
  481. LOCKREGION(dbenv, lt);
  482. /* Find the locker's last lock. */
  483. LOCKER_LOCK(lt, region, info->last_locker_id, ndx);
  484. if ((ret = __lock_getlocker(lt,
  485.     info->last_locker_id, ndx, 0, &lockerp)) != 0 || lockerp == NULL) {
  486. if (ret == 0)
  487. ret = DB_ALREADY_ABORTED;
  488. goto out;
  489. }
  490. lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
  491. /*
  492.  * It's possible that this locker was already aborted.  If that's
  493.  * the case, make sure that we remove its locker from the hash table.
  494.  */
  495. if (lockp == NULL) {
  496. if (LOCKER_FREEABLE(lockerp)) {
  497. __lock_freelocker(lt, region, lockerp, ndx);
  498. goto out;
  499. }
  500. } else if (R_OFFSET(&lt->reginfo, lockp) != info->last_lock ||
  501.     lockp->status != DB_LSTAT_WAITING) {
  502. ret = DB_ALREADY_ABORTED;
  503. goto out;
  504. }
  505. sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
  506. SH_LIST_REMOVE(lockp, locker_links, __db_lock);
  507. /* Abort lock, take it off list, and wake up this lock. */
  508. SHOBJECT_LOCK(lt, region, sh_obj, ndx);
  509. lockp->status = DB_LSTAT_ABORTED;
  510. SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);
  511. /*
  512.  * Either the waiters list is now empty, in which case we remove
  513.  * it from dd_objs, or it is not empty, in which case we need to
  514.  * do promotion.
  515.  */
  516. if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)
  517. SH_TAILQ_REMOVE(&region->dd_objs,
  518.     sh_obj, dd_links, __db_lockobj);
  519. else
  520. ret = __lock_promote(lt, sh_obj, 0);
  521. MUTEX_UNLOCK(dbenv, &lockp->mutex);
  522. region->ndeadlocks++;
  523. UNLOCKREGION(dbenv, lt);
  524. return (0);
  525. out: UNLOCKREGION(dbenv, lt);
  526. return (ret);
  527. }
  528. #ifdef DIAGNOSTIC
  529. static void
  530. __dd_debug(dbenv, idmap, bitmap, nlockers)
  531. DB_ENV *dbenv;
  532. locker_info *idmap;
  533. u_int32_t *bitmap, nlockers;
  534. {
  535. u_int32_t i, j, *mymap, nentries;
  536. int ret;
  537. char *msgbuf;
  538. __db_err(dbenv, "Waitsfor arraynWaiter:tWaiting on:");
  539. /* Allocate space to print 10 bytes per item waited on. */
  540. #undef MSGBUF_LEN
  541. #define MSGBUF_LEN ((nlockers + 1) * 10 + 64)
  542. if ((ret = __os_malloc(dbenv, MSGBUF_LEN, NULL, &msgbuf)) != 0)
  543. return;
  544. nentries = ALIGN(nlockers, 32) / 32;
  545. for (mymap = bitmap, i = 0; i < nlockers; i++, mymap += nentries) {
  546. if (!idmap[i].valid)
  547. continue;
  548. sprintf(msgbuf, /* Waiter. */
  549.     "%lx/%lu:t", (u_long)idmap[i].id, (u_long)idmap[i].pgno);
  550. for (j = 0; j < nlockers; j++)
  551. if (ISSET_MAP(mymap, j))
  552. sprintf(msgbuf, "%s %lx", msgbuf,
  553.     (u_long)idmap[j].id);
  554. (void)sprintf(msgbuf,
  555.     "%s %lu", msgbuf, (u_long)idmap[i].last_lock);
  556. __db_err(dbenv, msgbuf);
  557. }
  558. __os_free(msgbuf, MSGBUF_LEN);
  559. }
  560. #endif