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

MySQL数据库

开发平台:

Visual C++

  1. rec_t* sup;
  2. lock_mutex_enter_kernel();
  3. lock = lock_rec_get_first_on_page(page);
  4. if (lock == NULL) {
  5. lock_mutex_exit_kernel();
  6. return;
  7. }
  8. heap = mem_heap_create(256);
  9. /* Copy first all the locks on the page to heap and reset the
  10. bitmaps in the original locks; chain the copies of the locks
  11. using the trx_locks field in them. */
  12. UT_LIST_INIT(old_locks);
  13. while (lock != NULL) {
  14. /* Make a copy of the lock */
  15. old_lock = lock_rec_copy(lock, heap);
  16. UT_LIST_ADD_LAST(trx_locks, old_locks, old_lock);
  17. /* Reset bitmap of lock */
  18. lock_rec_bitmap_reset(lock);
  19. if (lock_get_wait(lock)) {
  20. lock_reset_lock_and_trx_wait(lock);
  21. }
  22. lock = lock_rec_get_next_on_page(lock);
  23. }
  24. sup = page_get_supremum_rec(page);
  25. lock = UT_LIST_GET_FIRST(old_locks);
  26. while (lock) {
  27. /* NOTE: we copy also the locks set on the infimum and
  28. supremum of the page; the infimum may carry locks if an
  29. update of a record is occurring on the page, and its locks
  30. were temporarily stored on the infimum */
  31. page_cur_set_before_first(page, &cur1);
  32. page_cur_set_before_first(old_page, &cur2);
  33. /* Set locks according to old locks */
  34. for (;;) {
  35. ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
  36. page_cur_get_rec(&cur2),
  37. rec_get_data_size(
  38.    page_cur_get_rec(&cur2))));
  39. old_heap_no = rec_get_heap_no(page_cur_get_rec(&cur2));
  40. if (lock_rec_get_nth_bit(lock, old_heap_no)) {
  41. /* NOTE that the old lock bitmap could be too
  42. small for the new heap number! */
  43. lock_rec_add_to_queue(lock->type_mode,
  44. page_cur_get_rec(&cur1),
  45. lock->index, lock->trx);
  46. /* if ((page_cur_get_rec(&cur1) == sup)
  47. && lock_get_wait(lock)) {
  48. fprintf(stderr,
  49. "---n--n!!!Lock reorg: supr type %lun",
  50. lock->type_mode);
  51. } */
  52. }
  53. if (page_cur_get_rec(&cur1) == sup) {
  54. break;
  55. }
  56. page_cur_move_to_next(&cur1);
  57. page_cur_move_to_next(&cur2);
  58. }
  59. /* Remember that we chained old locks on the trx_locks field: */
  60. lock = UT_LIST_GET_NEXT(trx_locks, lock);
  61. }
  62. lock_mutex_exit_kernel();
  63. mem_heap_free(heap);
  64. /*  ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page),
  65. buf_frame_get_page_no(page))); */
  66. }
  67. /*****************************************************************
  68. Moves the explicit locks on user records to another page if a record
  69. list end is moved to another page. */
  70. void
  71. lock_move_rec_list_end(
  72. /*===================*/
  73. page_t* new_page, /* in: index page to move to */
  74. page_t* page, /* in: index page */
  75. rec_t* rec) /* in: record on page: this is the
  76. first record moved */
  77. {
  78. lock_t* lock;
  79. page_cur_t cur1;
  80. page_cur_t cur2;
  81. ulint heap_no;
  82. rec_t* sup;
  83. ulint type_mode;
  84. lock_mutex_enter_kernel();
  85. /* Note: when we move locks from record to record, waiting locks
  86. and possible granted gap type locks behind them are enqueued in
  87. the original order, because new elements are inserted to a hash
  88. table to the end of the hash chain, and lock_rec_add_to_queue
  89. does not reuse locks if there are waiters in the queue. */
  90. sup = page_get_supremum_rec(page);
  91. lock = lock_rec_get_first_on_page(page);
  92. while (lock != NULL) {
  93. page_cur_position(rec, &cur1);
  94. if (page_cur_is_before_first(&cur1)) {
  95. page_cur_move_to_next(&cur1);
  96. }
  97. page_cur_set_before_first(new_page, &cur2);
  98. page_cur_move_to_next(&cur2);
  99. /* Copy lock requests on user records to new page and
  100. reset the lock bits on the old */
  101. while (page_cur_get_rec(&cur1) != sup) {
  102. ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
  103. page_cur_get_rec(&cur2),
  104. rec_get_data_size(
  105.    page_cur_get_rec(&cur2))));
  106. heap_no = rec_get_heap_no(page_cur_get_rec(&cur1));
  107. if (lock_rec_get_nth_bit(lock, heap_no)) {
  108. type_mode = lock->type_mode;
  109. lock_rec_reset_nth_bit(lock, heap_no);
  110. if (lock_get_wait(lock)) {
  111. lock_reset_lock_and_trx_wait(lock);
  112. }
  113. lock_rec_add_to_queue(type_mode,
  114. page_cur_get_rec(&cur2),
  115. lock->index, lock->trx);
  116. }
  117. page_cur_move_to_next(&cur1);
  118. page_cur_move_to_next(&cur2);
  119. }
  120. lock = lock_rec_get_next_on_page(lock);
  121. }
  122. lock_mutex_exit_kernel();
  123. /* ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page),
  124. buf_frame_get_page_no(page)));
  125. ut_ad(lock_rec_validate_page(buf_frame_get_space_id(new_page),
  126. buf_frame_get_page_no(new_page))); */
  127. }
  128. /*****************************************************************
  129. Moves the explicit locks on user records to another page if a record
  130. list start is moved to another page. */
  131. void
  132. lock_move_rec_list_start(
  133. /*=====================*/
  134. page_t* new_page, /* in: index page to move to */
  135. page_t* page, /* in: index page */
  136. rec_t* rec, /* in: record on page: this is the
  137. first record NOT copied */
  138. rec_t* old_end) /* in: old previous-to-last record on
  139. new_page before the records were copied */
  140. {
  141. lock_t* lock;
  142. page_cur_t cur1;
  143. page_cur_t cur2;
  144. ulint heap_no;
  145. ulint type_mode;
  146. ut_a(new_page);
  147. lock_mutex_enter_kernel();
  148. lock = lock_rec_get_first_on_page(page);
  149. while (lock != NULL) {
  150. page_cur_set_before_first(page, &cur1);
  151. page_cur_move_to_next(&cur1);
  152. page_cur_position(old_end, &cur2);
  153. page_cur_move_to_next(&cur2);
  154. /* Copy lock requests on user records to new page and
  155. reset the lock bits on the old */
  156. while (page_cur_get_rec(&cur1) != rec) {
  157. ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
  158. page_cur_get_rec(&cur2),
  159. rec_get_data_size(
  160.    page_cur_get_rec(&cur2))));
  161. heap_no = rec_get_heap_no(page_cur_get_rec(&cur1));
  162. if (lock_rec_get_nth_bit(lock, heap_no)) {
  163. type_mode = lock->type_mode;
  164. lock_rec_reset_nth_bit(lock, heap_no);
  165. if (lock_get_wait(lock)) {
  166. lock_reset_lock_and_trx_wait(lock);
  167. }
  168. lock_rec_add_to_queue(type_mode,
  169. page_cur_get_rec(&cur2),
  170. lock->index, lock->trx);
  171. }
  172. page_cur_move_to_next(&cur1);
  173. page_cur_move_to_next(&cur2);
  174. }
  175. lock = lock_rec_get_next_on_page(lock);
  176. }
  177. lock_mutex_exit_kernel();
  178. /* ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page),
  179. buf_frame_get_page_no(page)));
  180. ut_ad(lock_rec_validate_page(buf_frame_get_space_id(new_page),
  181. buf_frame_get_page_no(new_page))); */
  182. }
  183. /*****************************************************************
  184. Updates the lock table when a page is split to the right. */
  185. void
  186. lock_update_split_right(
  187. /*====================*/
  188. page_t* right_page, /* in: right page */
  189. page_t* left_page) /* in: left page */
  190. {
  191. lock_mutex_enter_kernel();
  192. /* Move the locks on the supremum of the left page to the supremum
  193. of the right page */
  194. lock_rec_move(page_get_supremum_rec(right_page),
  195. page_get_supremum_rec(left_page));
  196. /* Inherit the locks to the supremum of left page from the successor
  197. of the infimum on right page */
  198. lock_rec_inherit_to_gap(page_get_supremum_rec(left_page),
  199. page_rec_get_next(page_get_infimum_rec(right_page)));
  200. lock_mutex_exit_kernel();
  201. }
  202. /*****************************************************************
  203. Updates the lock table when a page is merged to the right. */
  204. void
  205. lock_update_merge_right(
  206. /*====================*/
  207. rec_t* orig_succ, /* in: original successor of infimum
  208. on the right page before merge */
  209. page_t* left_page) /* in: merged index page which will be
  210. discarded */
  211. {
  212. lock_mutex_enter_kernel();
  213. /* Inherit the locks from the supremum of the left page to the
  214. original successor of infimum on the right page, to which the left
  215. page was merged */
  216. lock_rec_inherit_to_gap(orig_succ, page_get_supremum_rec(left_page));
  217. /* Reset the locks on the supremum of the left page, releasing
  218. waiting transactions */
  219. lock_rec_reset_and_release_wait(page_get_supremum_rec(left_page));
  220. lock_rec_free_all_from_discard_page(left_page);
  221. lock_mutex_exit_kernel();
  222. }
  223. /*****************************************************************
  224. Updates the lock table when the root page is copied to another in
  225. btr_root_raise_and_insert. Note that we leave lock structs on the
  226. root page, even though they do not make sense on other than leaf
  227. pages: the reason is that in a pessimistic update the infimum record
  228. of the root page will act as a dummy carrier of the locks of the record
  229. to be updated. */
  230. void
  231. lock_update_root_raise(
  232. /*===================*/
  233. page_t* new_page, /* in: index page to which copied */
  234. page_t* root) /* in: root page */
  235. {
  236. lock_mutex_enter_kernel();
  237. /* Move the locks on the supremum of the root to the supremum
  238. of new_page */
  239. lock_rec_move(page_get_supremum_rec(new_page),
  240. page_get_supremum_rec(root));
  241. lock_mutex_exit_kernel();
  242. }
  243. /*****************************************************************
  244. Updates the lock table when a page is copied to another and the original page
  245. is removed from the chain of leaf pages, except if page is the root! */
  246. void
  247. lock_update_copy_and_discard(
  248. /*=========================*/
  249. page_t* new_page, /* in: index page to which copied */
  250. page_t* page) /* in: index page; NOT the root! */
  251. {
  252. lock_mutex_enter_kernel();
  253. /* Move the locks on the supremum of the old page to the supremum
  254. of new_page */
  255. lock_rec_move(page_get_supremum_rec(new_page),
  256. page_get_supremum_rec(page));
  257. lock_rec_free_all_from_discard_page(page);
  258. lock_mutex_exit_kernel();
  259. }
  260. /*****************************************************************
  261. Updates the lock table when a page is split to the left. */
  262. void
  263. lock_update_split_left(
  264. /*===================*/
  265. page_t* right_page, /* in: right page */
  266. page_t* left_page) /* in: left page */
  267. {
  268. lock_mutex_enter_kernel();
  269. /* Inherit the locks to the supremum of the left page from the
  270. successor of the infimum on the right page */
  271. lock_rec_inherit_to_gap(page_get_supremum_rec(left_page),
  272. page_rec_get_next(page_get_infimum_rec(right_page)));
  273. lock_mutex_exit_kernel();
  274. }
  275. /*****************************************************************
  276. Updates the lock table when a page is merged to the left. */
  277. void
  278. lock_update_merge_left(
  279. /*===================*/
  280. page_t* left_page, /* in: left page to which merged */
  281. rec_t* orig_pred, /* in: original predecessor of supremum
  282. on the left page before merge */
  283. page_t* right_page) /* in: merged index page which will be
  284. discarded */
  285. {
  286. lock_mutex_enter_kernel();
  287. if (page_rec_get_next(orig_pred) != page_get_supremum_rec(left_page)) {
  288. /* Inherit the locks on the supremum of the left page to the
  289. first record which was moved from the right page */
  290. lock_rec_inherit_to_gap(page_rec_get_next(orig_pred),
  291. page_get_supremum_rec(left_page));
  292. /* Reset the locks on the supremum of the left page,
  293. releasing waiting transactions */
  294. lock_rec_reset_and_release_wait(page_get_supremum_rec(
  295. left_page));
  296. }
  297. /* Move the locks from the supremum of right page to the supremum
  298. of the left page */
  299. lock_rec_move(page_get_supremum_rec(left_page),
  300.  page_get_supremum_rec(right_page));
  301. lock_rec_free_all_from_discard_page(right_page);
  302. lock_mutex_exit_kernel();
  303. }
  304. /*****************************************************************
  305. Resets the original locks on heir and replaces them with gap type locks
  306. inherited from rec. */
  307. void
  308. lock_rec_reset_and_inherit_gap_locks(
  309. /*=================================*/
  310. rec_t* heir, /* in: heir record */
  311. rec_t* rec) /* in: record */
  312. {
  313. mutex_enter(&kernel_mutex);       
  314. lock_rec_reset_and_release_wait(heir);
  315. lock_rec_inherit_to_gap(heir, rec);
  316. mutex_exit(&kernel_mutex);       
  317. }
  318. /*****************************************************************
  319. Updates the lock table when a page is discarded. */
  320. void
  321. lock_update_discard(
  322. /*================*/
  323. rec_t* heir, /* in: record which will inherit the locks */
  324. page_t* page) /* in: index page which will be discarded */
  325. {
  326. rec_t* rec;
  327. lock_mutex_enter_kernel();
  328. if (NULL == lock_rec_get_first_on_page(page)) {
  329. /* No locks exist on page, nothing to do */
  330. lock_mutex_exit_kernel();
  331. return;
  332. }
  333. /* Inherit all the locks on the page to the record and reset all
  334. the locks on the page */
  335. rec = page_get_infimum_rec(page);
  336. for (;;) {
  337. lock_rec_inherit_to_gap(heir, rec);
  338. /* Reset the locks on rec, releasing waiting transactions */
  339. lock_rec_reset_and_release_wait(rec);
  340. if (rec == page_get_supremum_rec(page)) {
  341. break;
  342. }
  343. rec = page_rec_get_next(rec);
  344. }
  345. lock_rec_free_all_from_discard_page(page);
  346. lock_mutex_exit_kernel();
  347. }
  348. /*****************************************************************
  349. Updates the lock table when a new user record is inserted. */
  350. void
  351. lock_update_insert(
  352. /*===============*/
  353. rec_t* rec) /* in: the inserted record */
  354. {
  355. lock_mutex_enter_kernel();
  356. /* Inherit the gap-locking locks for rec, in gap mode, from the next
  357. record */
  358. lock_rec_inherit_to_gap_if_gap_lock(rec, page_rec_get_next(rec));
  359. lock_mutex_exit_kernel();
  360. }
  361. /*****************************************************************
  362. Updates the lock table when a record is removed. */
  363. void
  364. lock_update_delete(
  365. /*===============*/
  366. rec_t* rec) /* in: the record to be removed */
  367. {
  368. lock_mutex_enter_kernel();
  369. /* Let the next record inherit the locks from rec, in gap mode */
  370. lock_rec_inherit_to_gap(page_rec_get_next(rec), rec);
  371. /* Reset the lock bits on rec and release waiting transactions */
  372. lock_rec_reset_and_release_wait(rec);
  373. lock_mutex_exit_kernel();
  374. }
  375.  
  376. /*************************************************************************
  377. Stores on the page infimum record the explicit locks of another record.
  378. This function is used to store the lock state of a record when it is
  379. updated and the size of the record changes in the update. The record
  380. is moved in such an update, perhaps to another page. The infimum record
  381. acts as a dummy carrier record, taking care of lock releases while the
  382. actual record is being moved. */
  383. void
  384. lock_rec_store_on_page_infimum(
  385. /*===========================*/
  386. rec_t* rec) /* in: record whose lock state is stored
  387. on the infimum record of the same page; lock
  388. bits are reset on the record */
  389. {
  390. page_t* page;
  391. page = buf_frame_align(rec);
  392. lock_mutex_enter_kernel();
  393. lock_rec_move(page_get_infimum_rec(page), rec);
  394. lock_mutex_exit_kernel();
  395. }
  396. /*************************************************************************
  397. Restores the state of explicit lock requests on a single record, where the
  398. state was stored on the infimum of the page. */
  399. void
  400. lock_rec_restore_from_page_infimum(
  401. /*===============================*/
  402. rec_t* rec, /* in: record whose lock state is restored */
  403. page_t* page) /* in: page (rec is not necessarily on this page)
  404. whose infimum stored the lock state; lock bits are
  405. reset on the infimum */ 
  406. {
  407. lock_mutex_enter_kernel();
  408. lock_rec_move(rec, page_get_infimum_rec(page));
  409. lock_mutex_exit_kernel();
  410. }
  411. /*=========== DEADLOCK CHECKING ======================================*/
  412. /************************************************************************
  413. Checks if a lock request results in a deadlock. */
  414. static
  415. ibool
  416. lock_deadlock_occurs(
  417. /*=================*/
  418. /* out: TRUE if a deadlock was detected and we
  419. chose trx as a victim; FALSE if no deadlock, or
  420. there was a deadlock, but we chose other
  421. transaction(s) as victim(s) */
  422. lock_t* lock, /* in: lock the transaction is requesting */
  423. trx_t* trx) /* in: transaction */
  424. {
  425. dict_table_t* table;
  426. dict_index_t* index;
  427. trx_t* mark_trx;
  428. ulint ret;
  429. ulint cost = 0;
  430. ut_ad(trx && lock);
  431. #ifdef UNIV_SYNC_DEBUG
  432. ut_ad(mutex_own(&kernel_mutex));
  433. #endif /* UNIV_SYNC_DEBUG */
  434. retry:
  435. /* We check that adding this trx to the waits-for graph
  436. does not produce a cycle. First mark all active transactions
  437. with 0: */
  438. mark_trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
  439. while (mark_trx) {
  440. mark_trx->deadlock_mark = 0;
  441. mark_trx = UT_LIST_GET_NEXT(trx_list, mark_trx);
  442. }
  443. ret = lock_deadlock_recursive(trx, trx, lock, &cost);
  444. if (ret == LOCK_VICTIM_IS_OTHER) {
  445. /* We chose some other trx as a victim: retry if there still
  446. is a deadlock */
  447. goto retry;
  448. }
  449. if (ret == LOCK_VICTIM_IS_START) {
  450. if (lock_get_type(lock) & LOCK_TABLE) {
  451. table = lock->un_member.tab_lock.table;
  452. index = NULL;
  453. } else {
  454. index = lock->index;
  455. table = index->table;
  456. }
  457. lock_deadlock_found = TRUE;
  458. fputs("*** WE ROLL BACK TRANSACTION (2)n",
  459. lock_latest_err_file);
  460. return(TRUE);
  461. }
  462. return(FALSE);
  463. }
  464. /************************************************************************
  465. Looks recursively for a deadlock. */
  466. static
  467. ulint
  468. lock_deadlock_recursive(
  469. /*====================*/
  470. /* out: 0 if no deadlock found,
  471. LOCK_VICTIM_IS_START if there was a deadlock
  472. and we chose 'start' as the victim,
  473. LOCK_VICTIM_IS_OTHER if a deadlock
  474. was found and we chose some other trx as a
  475. victim: we must do the search again in this
  476. last case because there may be another
  477. deadlock! */
  478. trx_t* start, /* in: recursion starting point */
  479. trx_t* trx, /* in: a transaction waiting for a lock */
  480. lock_t* wait_lock, /* in: the lock trx is waiting to be granted */
  481. ulint* cost) /* in/out: number of calculation steps thus
  482. far: if this exceeds LOCK_MAX_N_STEPS_...
  483. we return LOCK_VICTIM_IS_START */
  484. {
  485. lock_t* lock;
  486. ulint bit_no = ULINT_UNDEFINED;
  487. trx_t* lock_trx;
  488. ulint ret;
  489. ut_a(trx && start && wait_lock);
  490. #ifdef UNIV_SYNC_DEBUG
  491. ut_ad(mutex_own(&kernel_mutex));
  492. #endif /* UNIV_SYNC_DEBUG */
  493. if (trx->deadlock_mark == 1) {
  494. /* We have already exhaustively searched the subtree starting
  495. from this trx */
  496. return(0);
  497. }
  498. *cost = *cost + 1;
  499. if (*cost > LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK) {
  500. return(LOCK_VICTIM_IS_START);
  501. }
  502. lock = wait_lock;
  503. if (lock_get_type(wait_lock) == LOCK_REC) {
  504. bit_no = lock_rec_find_set_bit(wait_lock);
  505. ut_a(bit_no != ULINT_UNDEFINED);
  506. }
  507. /* Look at the locks ahead of wait_lock in the lock queue */
  508. for (;;) {
  509. if (lock_get_type(lock) & LOCK_TABLE) {
  510. lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
  511. } else {
  512. ut_ad(lock_get_type(lock) == LOCK_REC);
  513. ut_a(bit_no != ULINT_UNDEFINED);
  514. lock = lock_rec_get_prev(lock, bit_no);
  515. }
  516. if (lock == NULL) {
  517. /* We can mark this subtree as searched */
  518. trx->deadlock_mark = 1;
  519. return(FALSE);
  520. }
  521. if (lock_has_to_wait(wait_lock, lock)) {
  522. lock_trx = lock->trx;
  523. if (lock_trx == start) {
  524. /* We came back to the recursion starting
  525. point: a deadlock detected */
  526. FILE* ef = lock_latest_err_file;
  527. rewind(ef);
  528. ut_print_timestamp(ef);
  529. fputs("n*** (1) TRANSACTION:n", ef);
  530. trx_print(ef, wait_lock->trx);
  531. fputs(
  532. "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:n", ef);
  533. if (lock_get_type(wait_lock) == LOCK_REC) {
  534. lock_rec_print(ef, wait_lock);
  535. } else {
  536. lock_table_print(ef, wait_lock);
  537. }
  538. fputs("*** (2) TRANSACTION:n", ef);
  539. trx_print(ef, lock->trx);
  540. fputs("*** (2) HOLDS THE LOCK(S):n", ef);
  541. if (lock_get_type(lock) == LOCK_REC) {
  542. lock_rec_print(ef, lock);
  543. } else {
  544. lock_table_print(ef, lock);
  545. }
  546. fputs(
  547. "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:n", ef);
  548. if (lock_get_type(start->wait_lock)
  549. == LOCK_REC) {
  550. lock_rec_print(ef, start->wait_lock);
  551. } else {
  552. lock_table_print(ef, start->wait_lock);
  553. }
  554. if (lock_print_waits) {
  555. fputs("Deadlock detectedn", stderr);
  556. }
  557. if (ut_dulint_cmp(wait_lock->trx->undo_no,
  558. start->undo_no) >= 0) {
  559. /* Our recursion starting point
  560. transaction is 'smaller', let us
  561. choose 'start' as the victim and roll
  562. back it */
  563. return(LOCK_VICTIM_IS_START);
  564. }
  565. lock_deadlock_found = TRUE;
  566. /* Let us choose the transaction of wait_lock
  567. as a victim to try to avoid deadlocking our
  568. recursion starting point transaction */
  569. fputs("*** WE ROLL BACK TRANSACTION (1)n",
  570. ef);
  571. wait_lock->trx->was_chosen_as_deadlock_victim
  572. = TRUE;
  573. lock_cancel_waiting_and_release(wait_lock);
  574. /* Since trx and wait_lock are no longer
  575. in the waits-for graph, we can return FALSE;
  576. note that our selective algorithm can choose
  577. several transactions as victims, but still
  578. we may end up rolling back also the recursion
  579. starting point transaction! */
  580. return(LOCK_VICTIM_IS_OTHER);
  581. }
  582. if (lock_trx->que_state == TRX_QUE_LOCK_WAIT) {
  583. /* Another trx ahead has requested lock in an
  584. incompatible mode, and is itself waiting for
  585. a lock */
  586. ret = lock_deadlock_recursive(start, lock_trx,
  587. lock_trx->wait_lock, cost);
  588. if (ret != 0) {
  589. return(ret);
  590. }
  591. }
  592. }
  593. }/* end of the 'for (;;)'-loop */
  594. }
  595. /*========================= TABLE LOCKS ==============================*/
  596. /*************************************************************************
  597. Creates a table lock object and adds it as the last in the lock queue
  598. of the table. Does NOT check for deadlocks or lock compatibility. */
  599. UNIV_INLINE
  600. lock_t*
  601. lock_table_create(
  602. /*==============*/
  603. /* out, own: new lock object, or NULL if
  604. out of memory */
  605. dict_table_t* table, /* in: database table in dictionary cache */
  606. ulint type_mode,/* in: lock mode possibly ORed with
  607. LOCK_WAIT */
  608. trx_t* trx) /* in: trx */
  609. {
  610. lock_t* lock;
  611. ut_ad(table && trx);
  612. #ifdef UNIV_SYNC_DEBUG
  613. ut_ad(mutex_own(&kernel_mutex));
  614. #endif /* UNIV_SYNC_DEBUG */
  615. if (type_mode == LOCK_AUTO_INC) {
  616. /* Only one trx can have the lock on the table
  617. at a time: we may use the memory preallocated
  618. to the table object */
  619. lock = table->auto_inc_lock;
  620. ut_a(trx->auto_inc_lock == NULL);
  621. trx->auto_inc_lock = lock;
  622. } else {
  623. lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t));
  624. }
  625. if (lock == NULL) {
  626. return(NULL);
  627. }
  628. UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
  629. lock->type_mode = type_mode | LOCK_TABLE;
  630. lock->trx = trx;
  631. if (lock_get_type(lock) == LOCK_TABLE_EXP) {
  632. lock->trx->n_lock_table_exp++;
  633. }
  634. lock->un_member.tab_lock.table = table;
  635. UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
  636. if (type_mode & LOCK_WAIT) {
  637. lock_set_lock_and_trx_wait(lock, trx);
  638. }
  639. return(lock);
  640. }
  641. /*****************************************************************
  642. Removes a table lock request from the queue and the trx list of locks;
  643. this is a low-level function which does NOT check if waiting requests
  644. can now be granted. */
  645. UNIV_INLINE
  646. void
  647. lock_table_remove_low(
  648. /*==================*/
  649. lock_t* lock) /* in: table lock */
  650. {
  651. dict_table_t* table;
  652. trx_t* trx;
  653. #ifdef UNIV_SYNC_DEBUG
  654. ut_ad(mutex_own(&kernel_mutex));
  655. #endif /* UNIV_SYNC_DEBUG */
  656. table = lock->un_member.tab_lock.table;
  657. trx = lock->trx;
  658. if (lock == trx->auto_inc_lock) {
  659. trx->auto_inc_lock = NULL;
  660. }
  661. if (lock_get_type(lock) == LOCK_TABLE_EXP) {
  662. lock->trx->n_lock_table_exp--;
  663. }
  664. UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
  665. UT_LIST_REMOVE(un_member.tab_lock.locks, table->locks, lock);
  666. }
  667. /*************************************************************************
  668. Enqueues a waiting request for a table lock which cannot be granted
  669. immediately. Checks for deadlocks. */
  670. static
  671. ulint
  672. lock_table_enqueue_waiting(
  673. /*=======================*/
  674. /* out: DB_LOCK_WAIT, DB_DEADLOCK, or
  675. DB_QUE_THR_SUSPENDED, or DB_SUCCESS;
  676. DB_SUCCESS means that there was a deadlock,
  677. but another transaction was chosen as a
  678. victim, and we got the lock immediately:
  679. no need to wait then */
  680. ulint mode, /* in: lock mode this transaction is
  681. requesting */
  682. dict_table_t* table, /* in: table */
  683. que_thr_t* thr) /* in: query thread */
  684. {
  685. lock_t* lock;
  686. trx_t* trx;
  687. #ifdef UNIV_SYNC_DEBUG
  688. ut_ad(mutex_own(&kernel_mutex));
  689. #endif /* UNIV_SYNC_DEBUG */
  690. /* Test if there already is some other reason to suspend thread:
  691. we do not enqueue a lock request if the query thread should be
  692. stopped anyway */
  693. if (que_thr_stop(thr)) {
  694. ut_error;
  695. return(DB_QUE_THR_SUSPENDED);
  696. }
  697. trx = thr_get_trx(thr);
  698. if (trx->dict_operation) {
  699. ut_print_timestamp(stderr);
  700. fputs(
  701. "  InnoDB: Error: a table lock wait happens in a dictionary operation!n"
  702. "InnoDB: Table name ", stderr);
  703. ut_print_name(stderr, trx, table->name);
  704. fputs(".n"
  705. "InnoDB: Submit a detailed bug report to http://bugs.mysql.comn",
  706. stderr);
  707. }
  708. /* Enqueue the lock request that will wait to be granted */
  709. lock = lock_table_create(table, mode | LOCK_WAIT, trx);
  710. /* Check if a deadlock occurs: if yes, remove the lock request and
  711. return an error code */
  712. if (lock_deadlock_occurs(lock, trx)) {
  713. lock_reset_lock_and_trx_wait(lock);
  714. lock_table_remove_low(lock);
  715. return(DB_DEADLOCK);
  716. }
  717. if (trx->wait_lock == NULL) {
  718. /* Deadlock resolution chose another transaction as a victim,
  719. and we accidentally got our lock granted! */
  720. return(DB_SUCCESS);
  721. }
  722. trx->que_state = TRX_QUE_LOCK_WAIT;
  723. trx->was_chosen_as_deadlock_victim = FALSE;
  724. trx->wait_started = time(NULL);
  725. ut_a(que_thr_stop(thr));
  726. return(DB_LOCK_WAIT);
  727. }
  728. /*************************************************************************
  729. Checks if other transactions have an incompatible mode lock request in
  730. the lock queue. */
  731. UNIV_INLINE
  732. ibool
  733. lock_table_other_has_incompatible(
  734. /*==============================*/
  735. trx_t* trx, /* in: transaction, or NULL if all
  736. transactions should be included */
  737. ulint wait, /* in: LOCK_WAIT if also waiting locks are
  738. taken into account, or 0 if not */
  739. dict_table_t* table, /* in: table */
  740. ulint mode) /* in: lock mode */
  741. {
  742. lock_t* lock;
  743. #ifdef UNIV_SYNC_DEBUG
  744. ut_ad(mutex_own(&kernel_mutex));
  745. #endif /* UNIV_SYNC_DEBUG */
  746. lock = UT_LIST_GET_LAST(table->locks);
  747. while (lock != NULL) {
  748. if ((lock->trx != trx) 
  749.     && (!lock_mode_compatible(lock_get_mode(lock), mode))
  750.     && (wait || !(lock_get_wait(lock)))) {
  751.      return(TRUE);
  752. }
  753. lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
  754. }
  755. return(FALSE);
  756. }
  757. /*************************************************************************
  758. Locks the specified database table in the mode given. If the lock cannot
  759. be granted immediately, the query thread is put to wait. */
  760. ulint
  761. lock_table(
  762. /*=======*/
  763. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  764. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  765. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  766. does nothing;
  767. if LOCK_TABLE_EXP bits are set,
  768. creates an explicit table lock */
  769. dict_table_t* table, /* in: database table in dictionary cache */
  770. ulint mode, /* in: lock mode */
  771. que_thr_t* thr) /* in: query thread */
  772. {
  773. trx_t* trx;
  774. ulint err;
  775. ut_ad(table && thr);
  776. if (flags & BTR_NO_LOCKING_FLAG) {
  777. return(DB_SUCCESS);
  778. }
  779. ut_a(flags == 0 || flags == LOCK_TABLE_EXP);
  780. trx = thr_get_trx(thr);
  781. lock_mutex_enter_kernel();
  782. /* Look for stronger locks the same trx already has on the table */
  783. if (lock_table_has(trx, table, mode)) {
  784. lock_mutex_exit_kernel();
  785. return(DB_SUCCESS);
  786. }
  787. /* We have to check if the new lock is compatible with any locks
  788. other transactions have in the table lock queue. */
  789. if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) {
  790. /* Another trx has a request on the table in an incompatible
  791. mode: this trx may have to wait */
  792. err = lock_table_enqueue_waiting(mode, table, thr);
  793. lock_mutex_exit_kernel();
  794. return(err);
  795. }
  796. lock_table_create(table, mode | flags, trx);
  797. ut_a(!flags || mode == LOCK_S || mode == LOCK_X);
  798. lock_mutex_exit_kernel();
  799. return(DB_SUCCESS);
  800. }
  801. /*************************************************************************
  802. Checks if there are any locks set on the table. */
  803. ibool
  804. lock_is_on_table(
  805. /*=============*/
  806. /* out: TRUE if there are lock(s) */
  807. dict_table_t* table) /* in: database table in dictionary cache */
  808. {
  809. ibool ret;
  810. ut_ad(table);
  811. lock_mutex_enter_kernel();
  812. if (UT_LIST_GET_LAST(table->locks)) {
  813. ret = TRUE;
  814. } else {
  815. ret = FALSE;
  816. }
  817. lock_mutex_exit_kernel();
  818. return(ret);
  819. }
  820. /*************************************************************************
  821. Checks if a waiting table lock request still has to wait in a queue. */
  822. static
  823. ibool
  824. lock_table_has_to_wait_in_queue(
  825. /*============================*/
  826. /* out: TRUE if still has to wait */
  827. lock_t* wait_lock) /* in: waiting table lock */
  828. {
  829. dict_table_t* table;
  830. lock_t* lock;
  831.   ut_ad(lock_get_wait(wait_lock));
  832.  
  833. table = wait_lock->un_member.tab_lock.table;
  834. lock = UT_LIST_GET_FIRST(table->locks);
  835. while (lock != wait_lock) {
  836. if (lock_has_to_wait(wait_lock, lock)) {
  837.      return(TRUE);
  838. }
  839. lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
  840. }
  841. return(FALSE);
  842. }
  843. /*****************************************************************
  844. Removes a table lock request, waiting or granted, from the queue and grants
  845. locks to other transactions in the queue, if they now are entitled to a
  846. lock. */
  847. static
  848. void
  849. lock_table_dequeue(
  850. /*===============*/
  851. lock_t* in_lock)/* in: table lock object; transactions waiting
  852. behind will get their lock requests granted, if
  853. they are now qualified to it */
  854. {
  855. lock_t* lock;
  856. #ifdef UNIV_SYNC_DEBUG
  857. ut_ad(mutex_own(&kernel_mutex));
  858. #endif /* UNIV_SYNC_DEBUG */
  859. ut_a(lock_get_type(in_lock) == LOCK_TABLE ||
  860. lock_get_type(in_lock) == LOCK_TABLE_EXP);
  861. lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
  862. lock_table_remove_low(in_lock);
  863. /* Check if waiting locks in the queue can now be granted: grant
  864. locks if there are no conflicting locks ahead. */
  865. while (lock != NULL) {
  866. if (lock_get_wait(lock)
  867. && !lock_table_has_to_wait_in_queue(lock)) {
  868. /* Grant the lock */
  869. lock_grant(lock);
  870. }
  871. lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
  872. }
  873. }
  874. /*=========================== LOCK RELEASE ==============================*/
  875. /*************************************************************************
  876. Releases a table lock.
  877. Releases possible other transactions waiting for this lock. */
  878. void
  879. lock_table_unlock(
  880. /*==============*/
  881. lock_t* lock) /* in: lock */
  882. {
  883. mutex_enter(&kernel_mutex);
  884. lock_table_dequeue(lock);
  885. mutex_exit(&kernel_mutex);
  886. }
  887. /*************************************************************************
  888. Releases an auto-inc lock a transaction possibly has on a table.
  889. Releases possible other transactions waiting for this lock. */
  890. void
  891. lock_table_unlock_auto_inc(
  892. /*=======================*/
  893. trx_t* trx) /* in: transaction */
  894. {
  895. if (trx->auto_inc_lock) {
  896. mutex_enter(&kernel_mutex);
  897. lock_table_dequeue(trx->auto_inc_lock);
  898. mutex_exit(&kernel_mutex);
  899. }
  900. }
  901. /*************************************************************************
  902. Releases transaction locks, and releases possible other transactions waiting
  903. because of these locks. */
  904. void
  905. lock_release_off_kernel(
  906. /*====================*/
  907. trx_t* trx) /* in: transaction */
  908. {
  909. dict_table_t* table;
  910. ulint count;
  911. lock_t* lock;
  912. #ifdef UNIV_SYNC_DEBUG
  913. ut_ad(mutex_own(&kernel_mutex));
  914. #endif /* UNIV_SYNC_DEBUG */
  915. lock = UT_LIST_GET_LAST(trx->trx_locks);
  916. count = 0;
  917. while (lock != NULL) {
  918. count++;
  919. if (lock_get_type(lock) == LOCK_REC) {
  920. lock_rec_dequeue_from_page(lock);
  921. } else {
  922. ut_ad(lock_get_type(lock) & LOCK_TABLE);
  923. if (lock_get_mode(lock) != LOCK_IS
  924.     && 0 != ut_dulint_cmp(trx->undo_no,
  925.   ut_dulint_zero)) {
  926. /* The trx may have modified the table.
  927. We block the use of the MySQL query cache
  928. for all currently active transactions. */
  929. table = lock->un_member.tab_lock.table;
  930. table->query_cache_inv_trx_id =
  931. trx_sys->max_trx_id;
  932. }
  933. lock_table_dequeue(lock);
  934. if (lock_get_type(lock) == LOCK_TABLE_EXP) {
  935. ut_a(lock_get_mode(lock) == LOCK_S
  936. || lock_get_mode(lock) == LOCK_X);
  937. }
  938. }
  939. if (count == LOCK_RELEASE_KERNEL_INTERVAL) {
  940. /* Release the kernel mutex for a while, so that we
  941. do not monopolize it */
  942. lock_mutex_exit_kernel();
  943. lock_mutex_enter_kernel();
  944. count = 0;
  945. }
  946. lock = UT_LIST_GET_LAST(trx->trx_locks);
  947. }
  948. mem_heap_empty(trx->lock_heap);
  949. ut_a(trx->auto_inc_lock == NULL);
  950. ut_a(trx->n_lock_table_exp == 0);
  951. }
  952. /*************************************************************************
  953. Releases table locks explicitly requested with LOCK TABLES (indicated by
  954. lock type LOCK_TABLE_EXP), and releases possible other transactions waiting
  955. because of these locks. */
  956. void
  957. lock_release_tables_off_kernel(
  958. /*===========================*/
  959. trx_t* trx) /* in: transaction */
  960. {
  961. dict_table_t* table;
  962. ulint count;
  963. lock_t* lock;
  964. #ifdef UNIV_SYNC_DEBUG
  965. ut_ad(mutex_own(&kernel_mutex));
  966. #endif /* UNIV_SYNC_DEBUG */
  967. lock = UT_LIST_GET_LAST(trx->trx_locks);
  968. count = 0;
  969. while (lock != NULL) {
  970. count++;
  971. if (lock_get_type(lock) == LOCK_TABLE_EXP) {
  972. ut_a(lock_get_mode(lock) == LOCK_S
  973. || lock_get_mode(lock) == LOCK_X);
  974. if (trx->insert_undo || trx->update_undo) {
  975. /* The trx may have modified the table.
  976. We block the use of the MySQL query
  977. cache for all currently active
  978. transactions. */
  979. table = lock->un_member.tab_lock.table;
  980. table->query_cache_inv_trx_id =
  981. trx_sys->max_trx_id;
  982. }
  983. lock_table_dequeue(lock);
  984. lock = UT_LIST_GET_LAST(trx->trx_locks);
  985. continue;
  986. }
  987. if (count == LOCK_RELEASE_KERNEL_INTERVAL) {
  988. /* Release the kernel mutex for a while, so that we
  989. do not monopolize it */
  990. lock_mutex_exit_kernel();
  991. lock_mutex_enter_kernel();
  992. count = 0;
  993. }
  994. lock = UT_LIST_GET_PREV(trx_locks, lock);
  995. }
  996. ut_a(trx->n_lock_table_exp == 0);
  997. }
  998. /*************************************************************************
  999. Cancels a waiting lock request and releases possible other transactions
  1000. waiting behind it. */
  1001. void
  1002. lock_cancel_waiting_and_release(
  1003. /*============================*/
  1004. lock_t* lock) /* in: waiting lock request */
  1005. {
  1006. #ifdef UNIV_SYNC_DEBUG
  1007. ut_ad(mutex_own(&kernel_mutex));
  1008. #endif /* UNIV_SYNC_DEBUG */
  1009. if (lock_get_type(lock) == LOCK_REC) {
  1010. lock_rec_dequeue_from_page(lock);
  1011. } else {
  1012. ut_ad(lock_get_type(lock) & LOCK_TABLE);
  1013. lock_table_dequeue(lock);
  1014. }
  1015. /* Reset the wait flag and the back pointer to lock in trx */
  1016. lock_reset_lock_and_trx_wait(lock);
  1017. /* The following function releases the trx from lock wait */
  1018. trx_end_lock_wait(lock->trx);
  1019. }
  1020. /*************************************************************************
  1021. Resets all record and table locks of a transaction on a table to be dropped.
  1022. No lock is allowed to be a wait lock. */
  1023. static
  1024. void
  1025. lock_reset_all_on_table_for_trx(
  1026. /*============================*/
  1027. dict_table_t* table, /* in: table to be dropped */
  1028. trx_t* trx) /* in: a transaction */
  1029. {
  1030. lock_t* lock;
  1031. lock_t* prev_lock;
  1032. #ifdef UNIV_SYNC_DEBUG
  1033. ut_ad(mutex_own(&kernel_mutex));
  1034. #endif /* UNIV_SYNC_DEBUG */
  1035. lock = UT_LIST_GET_LAST(trx->trx_locks);
  1036. while (lock != NULL) {
  1037. prev_lock = UT_LIST_GET_PREV(trx_locks, lock);
  1038. if (lock_get_type(lock) == LOCK_REC
  1039. && lock->index->table == table) {
  1040. ut_a(!lock_get_wait(lock));
  1041. lock_rec_discard(lock);
  1042. } else if (lock_get_type(lock) & LOCK_TABLE
  1043. && lock->un_member.tab_lock.table == table) {
  1044. ut_a(!lock_get_wait(lock));
  1045. lock_table_remove_low(lock);
  1046. }
  1047. lock = prev_lock;
  1048. }
  1049. }
  1050. /*************************************************************************
  1051. Resets all locks, both table and record locks, on a table to be dropped.
  1052. No lock is allowed to be a wait lock. */
  1053. void
  1054. lock_reset_all_on_table(
  1055. /*====================*/
  1056. dict_table_t* table) /* in: table to be dropped */
  1057. {
  1058. lock_t* lock;
  1059. mutex_enter(&kernel_mutex);
  1060. lock = UT_LIST_GET_FIRST(table->locks);
  1061. while (lock) {
  1062. ut_a(!lock_get_wait(lock));
  1063. lock_reset_all_on_table_for_trx(table, lock->trx);
  1064. lock = UT_LIST_GET_FIRST(table->locks);
  1065. }
  1066. mutex_exit(&kernel_mutex);
  1067. }
  1068. /*===================== VALIDATION AND DEBUGGING  ====================*/
  1069. /*************************************************************************
  1070. Prints info of a table lock. */
  1071. void
  1072. lock_table_print(
  1073. /*=============*/
  1074. FILE* file, /* in: file where to print */
  1075. lock_t* lock) /* in: table type lock */
  1076. {
  1077. #ifdef UNIV_SYNC_DEBUG
  1078. ut_ad(mutex_own(&kernel_mutex));
  1079. #endif /* UNIV_SYNC_DEBUG */
  1080. ut_a(lock_get_type(lock) == LOCK_TABLE ||
  1081. lock_get_type(lock) == LOCK_TABLE_EXP);
  1082. if (lock_get_type(lock) == LOCK_TABLE_EXP) {
  1083. fputs("EXPLICIT ", file);
  1084. }
  1085. fputs("TABLE LOCK table ", file);
  1086. ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
  1087. fprintf(file, " trx id %lu %lu",
  1088. (ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low);
  1089. if (lock_get_mode(lock) == LOCK_S) {
  1090. fputs(" lock mode S", file);
  1091. } else if (lock_get_mode(lock) == LOCK_X) {
  1092. fputs(" lock mode X", file);
  1093. } else if (lock_get_mode(lock) == LOCK_IS) {
  1094. fputs(" lock mode IS", file);
  1095. } else if (lock_get_mode(lock) == LOCK_IX) {
  1096. fputs(" lock mode IX", file);
  1097. } else if (lock_get_mode(lock) == LOCK_AUTO_INC) {
  1098. fputs(" lock mode AUTO-INC", file);
  1099. } else {
  1100. fprintf(file, " unknown lock mode %lu", (ulong) lock_get_mode(lock));
  1101. }
  1102. if (lock_get_wait(lock)) {
  1103. fputs(" waiting", file);
  1104. }
  1105. putc('n', file);
  1106. }
  1107. /*************************************************************************
  1108. Prints info of a record lock. */
  1109. void
  1110. lock_rec_print(
  1111. /*===========*/
  1112. FILE* file, /* in: file where to print */
  1113. lock_t* lock) /* in: record type lock */
  1114. {
  1115. page_t* page;
  1116. ulint space;
  1117. ulint page_no;
  1118. ulint i;
  1119. mtr_t mtr;
  1120. #ifdef UNIV_SYNC_DEBUG
  1121. ut_ad(mutex_own(&kernel_mutex));
  1122. #endif /* UNIV_SYNC_DEBUG */
  1123. ut_a(lock_get_type(lock) == LOCK_REC);
  1124. space = lock->un_member.rec_lock.space;
  1125.   page_no = lock->un_member.rec_lock.page_no;
  1126. fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ",
  1127.        (ulong) space, (ulong) page_no,
  1128.        (ulong) lock_rec_get_n_bits(lock));
  1129. dict_index_name_print(file, lock->trx, lock->index);
  1130. fprintf(file, " trx id %lu %lu",
  1131.        (ulong) (lock->trx)->id.high,
  1132.        (ulong) (lock->trx)->id.low);
  1133. if (lock_get_mode(lock) == LOCK_S) {
  1134. fputs(" lock mode S", file);
  1135. } else if (lock_get_mode(lock) == LOCK_X) {
  1136. fputs(" lock_mode X", file);
  1137. } else {
  1138. ut_error;
  1139. }
  1140. if (lock_rec_get_gap(lock)) {
  1141. fputs(" locks gap before rec", file);
  1142. }
  1143. if (lock_rec_get_rec_not_gap(lock)) {
  1144. fputs(" locks rec but not gap", file);
  1145. }
  1146. if (lock_rec_get_insert_intention(lock)) {
  1147. fputs(" insert intention", file);
  1148. }
  1149. if (lock_get_wait(lock)) {
  1150. fputs(" waiting", file);
  1151. }
  1152. mtr_start(&mtr);
  1153. putc('n', file);
  1154. /* If the page is not in the buffer pool, we cannot load it
  1155. because we have the kernel mutex and ibuf operations would
  1156. break the latching order */
  1157. page = buf_page_get_gen(space, page_no, RW_NO_LATCH,
  1158. NULL, BUF_GET_IF_IN_POOL,
  1159. __FILE__, __LINE__, &mtr);
  1160. if (page) {
  1161. page = buf_page_get_nowait(space, page_no, RW_S_LATCH, &mtr);
  1162. if (!page) {
  1163. /* Let us try to get an X-latch. If the current thread
  1164. is holding an X-latch on the page, we cannot get an
  1165. S-latch. */
  1166. page = buf_page_get_nowait(space, page_no, RW_X_LATCH,
  1167. &mtr);
  1168. }
  1169. }
  1170. if (page) {
  1171. #ifdef UNIV_SYNC_DEBUG
  1172. buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK);
  1173. #endif /* UNIV_SYNC_DEBUG */
  1174. }
  1175. for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
  1176. if (lock_rec_get_nth_bit(lock, i)) {
  1177. fprintf(file, "Record lock, heap no %lu ", (ulong) i);
  1178. if (page) {
  1179. rec_print(file,
  1180.       page_find_rec_with_heap_no(page, i));
  1181. }
  1182. putc('n', file);
  1183. }
  1184. }
  1185. mtr_commit(&mtr);
  1186. }
  1187. /*************************************************************************
  1188. Calculates the number of record lock structs in the record lock hash table. */
  1189. static
  1190. ulint
  1191. lock_get_n_rec_locks(void)
  1192. /*======================*/
  1193. {
  1194. lock_t* lock;
  1195. ulint n_locks = 0;
  1196. ulint i;
  1197. #ifdef UNIV_SYNC_DEBUG
  1198. ut_ad(mutex_own(&kernel_mutex));
  1199. #endif /* UNIV_SYNC_DEBUG */
  1200. for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
  1201. lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
  1202. while (lock) {
  1203. n_locks++;
  1204. lock = HASH_GET_NEXT(hash, lock);
  1205. }
  1206. }
  1207. return(n_locks);
  1208. }
  1209. /*************************************************************************
  1210. Prints info of locks for all transactions. */
  1211. void
  1212. lock_print_info_summary(
  1213. /*====================*/
  1214. FILE* file) /* in: file where to print */
  1215. {
  1216. /* We must protect the MySQL thd->query field with a MySQL mutex, and
  1217. because the MySQL mutex must be reserved before the kernel_mutex of
  1218. InnoDB, we call innobase_mysql_prepare_print_arbitrary_thd() here. */
  1219. innobase_mysql_prepare_print_arbitrary_thd();
  1220. lock_mutex_enter_kernel();
  1221. if (lock_deadlock_found) {
  1222. fputs(
  1223. "------------------------n" 
  1224. "LATEST DETECTED DEADLOCKn"
  1225. "------------------------n", file);
  1226. ut_copy_file(file, lock_latest_err_file);
  1227. }
  1228. fputs(
  1229. "------------n" 
  1230. "TRANSACTIONSn"
  1231. "------------n", file);
  1232. fprintf(file, "Trx id counter %lu %lun",
  1233.        (ulong) ut_dulint_get_high(trx_sys->max_trx_id),
  1234.        (ulong) ut_dulint_get_low(trx_sys->max_trx_id));
  1235. fprintf(file,
  1236. "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lun",
  1237. (ulong) ut_dulint_get_high(purge_sys->purge_trx_no),
  1238. (ulong) ut_dulint_get_low(purge_sys->purge_trx_no),
  1239. (ulong) ut_dulint_get_high(purge_sys->purge_undo_no),
  1240. (ulong) ut_dulint_get_low(purge_sys->purge_undo_no));
  1241. fprintf(file,
  1242. "History list length %lun", (ulong) trx_sys->rseg_history_len);
  1243. fprintf(file,
  1244. "Total number of lock structs in row lock hash table %lun",
  1245.  (ulong) lock_get_n_rec_locks());
  1246. }
  1247. /*************************************************************************
  1248. Prints info of locks for each transaction. */
  1249. void
  1250. lock_print_info_all_transactions(
  1251. /*=============================*/
  1252. FILE* file) /* in: file where to print */
  1253. {
  1254. lock_t* lock;
  1255. ulint space;
  1256. ulint page_no;
  1257. page_t* page;
  1258. ibool load_page_first = TRUE;
  1259. ulint nth_trx = 0;
  1260. ulint nth_lock = 0;
  1261. ulint i;
  1262. mtr_t mtr;
  1263. trx_t* trx;
  1264. fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:n");
  1265. /* First print info on non-active transactions */
  1266. trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
  1267. while (trx) {
  1268. if (trx->conc_state == TRX_NOT_STARTED) {
  1269. fputs("---", file);
  1270. trx_print(file, trx);
  1271. }
  1272. trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
  1273. }
  1274. loop:
  1275. trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
  1276. i = 0;
  1277. /* Since we temporarily release the kernel mutex when
  1278. reading a database page in below, variable trx may be
  1279. obsolete now and we must loop through the trx list to
  1280. get probably the same trx, or some other trx. */
  1281. while (trx && (i < nth_trx)) {
  1282. trx = UT_LIST_GET_NEXT(trx_list, trx);
  1283. i++;
  1284. }
  1285. if (trx == NULL) {
  1286. lock_mutex_exit_kernel();
  1287. innobase_mysql_end_print_arbitrary_thd();
  1288. ut_ad(lock_validate());
  1289. return;
  1290. }
  1291. if (nth_lock == 0) {
  1292. fputs("---", file);
  1293. trx_print(file, trx);
  1294.         if (trx->read_view) {
  1295. fprintf(file,
  1296.        "Trx read view will not see trx with id >= %lu %lu, sees < %lu %lun",
  1297.       (ulong) ut_dulint_get_high(trx->read_view->low_limit_id),
  1298.               (ulong) ut_dulint_get_low(trx->read_view->low_limit_id),
  1299.               (ulong) ut_dulint_get_high(trx->read_view->up_limit_id),
  1300.               (ulong) ut_dulint_get_low(trx->read_view->up_limit_id));
  1301.         }
  1302. if (trx->que_state == TRX_QUE_LOCK_WAIT) {
  1303. fprintf(file,
  1304.  "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:n",
  1305.    (ulong)difftime(time(NULL), trx->wait_started));
  1306. if (lock_get_type(trx->wait_lock) == LOCK_REC) {
  1307. lock_rec_print(file, trx->wait_lock);
  1308. } else {
  1309. lock_table_print(file, trx->wait_lock);
  1310. }
  1311. fputs("------------------n", file);
  1312. }
  1313. }
  1314. if (!srv_print_innodb_lock_monitor) {
  1315.    nth_trx++;
  1316.    goto loop;
  1317. }
  1318. i = 0;
  1319. /* Look at the note about the trx loop above why we loop here:
  1320. lock may be an obsolete pointer now. */
  1321. lock = UT_LIST_GET_FIRST(trx->trx_locks);
  1322. while (lock && (i < nth_lock)) {
  1323. lock = UT_LIST_GET_NEXT(trx_locks, lock);
  1324. i++;
  1325. }
  1326. if (lock == NULL) {
  1327. nth_trx++;
  1328. nth_lock = 0;
  1329. goto loop;
  1330. }
  1331. if (lock_get_type(lock) == LOCK_REC) {
  1332. space = lock->un_member.rec_lock.space;
  1333.   page_no = lock->un_member.rec_lock.page_no;
  1334.   if (load_page_first) {
  1335. lock_mutex_exit_kernel();
  1336. innobase_mysql_end_print_arbitrary_thd();
  1337. mtr_start(&mtr);
  1338. page = buf_page_get_with_no_latch(space, page_no, &mtr);
  1339. mtr_commit(&mtr);
  1340. load_page_first = FALSE;
  1341. innobase_mysql_prepare_print_arbitrary_thd();
  1342. lock_mutex_enter_kernel();
  1343. goto loop;
  1344. }
  1345. lock_rec_print(file, lock);
  1346. } else {
  1347. ut_ad(lock_get_type(lock) & LOCK_TABLE);
  1348. lock_table_print(file, lock);
  1349. }
  1350. load_page_first = TRUE;
  1351. nth_lock++;
  1352. if (nth_lock >= 10) {
  1353. fputs(
  1354. "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTSn",
  1355. file);
  1356. nth_trx++;
  1357. nth_lock = 0;
  1358. goto loop;
  1359. }
  1360. goto loop;
  1361. }
  1362. /*************************************************************************
  1363. Validates the lock queue on a table. */
  1364. ibool
  1365. lock_table_queue_validate(
  1366. /*======================*/
  1367. /* out: TRUE if ok */
  1368. dict_table_t* table) /* in: table */
  1369. {
  1370. lock_t* lock;
  1371. ibool is_waiting;
  1372. #ifdef UNIV_SYNC_DEBUG
  1373. ut_ad(mutex_own(&kernel_mutex));
  1374. #endif /* UNIV_SYNC_DEBUG */
  1375. is_waiting = FALSE;
  1376. lock = UT_LIST_GET_FIRST(table->locks);
  1377. while (lock) {
  1378. ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
  1379.      || ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
  1380. if (!lock_get_wait(lock)) {
  1381. ut_a(!is_waiting);
  1382. ut_a(!lock_table_other_has_incompatible(lock->trx, 0,
  1383. table, lock_get_mode(lock)));
  1384. } else {
  1385. is_waiting = TRUE;
  1386. ut_a(lock_table_has_to_wait_in_queue(lock));
  1387. }
  1388. lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
  1389. }
  1390. return(TRUE);
  1391. }
  1392. /*************************************************************************
  1393. Validates the lock queue on a single record. */
  1394. ibool
  1395. lock_rec_queue_validate(
  1396. /*====================*/
  1397. /* out: TRUE if ok */
  1398. rec_t* rec, /* in: record to look at */
  1399. dict_index_t* index) /* in: index, or NULL if not known */
  1400. {
  1401. trx_t* impl_trx;
  1402. lock_t* lock;
  1403. ut_a(rec);
  1404. lock_mutex_enter_kernel();
  1405. if (page_rec_is_supremum(rec) || page_rec_is_infimum(rec)) {
  1406. lock = lock_rec_get_first(rec);
  1407. while (lock) {
  1408. ut_a(lock->trx->conc_state == TRX_ACTIVE
  1409.            || lock->trx->conc_state
  1410. == TRX_COMMITTED_IN_MEMORY);
  1411. ut_a(trx_in_trx_list(lock->trx));
  1412. if (lock_get_wait(lock)) {
  1413. ut_a(lock_rec_has_to_wait_in_queue(lock));
  1414. }
  1415. if (index) {
  1416. ut_a(lock->index == index);
  1417. }
  1418. lock = lock_rec_get_next(rec, lock);
  1419. }
  1420. lock_mutex_exit_kernel();
  1421.      return(TRUE);
  1422. }
  1423. if (index && (index->type & DICT_CLUSTERED)) {
  1424. impl_trx = lock_clust_rec_some_has_impl(rec, index);
  1425. if (impl_trx && lock_rec_other_has_expl_req(LOCK_S, 0,
  1426. LOCK_WAIT, rec, impl_trx)) {
  1427. ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
  1428. impl_trx));
  1429. }
  1430. }
  1431. if (index && !(index->type & DICT_CLUSTERED)) {
  1432. /* The kernel mutex may get released temporarily in the
  1433. next function call: we have to release lock table mutex
  1434. to obey the latching order */
  1435. impl_trx = lock_sec_rec_some_has_impl_off_kernel(rec, index);
  1436. if (impl_trx && lock_rec_other_has_expl_req(LOCK_S, 0,
  1437. LOCK_WAIT, rec, impl_trx)) {
  1438. ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
  1439. impl_trx));
  1440. }
  1441. }
  1442. lock = lock_rec_get_first(rec);
  1443. while (lock) {
  1444. ut_a(lock->trx->conc_state == TRX_ACTIVE
  1445.      || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
  1446. ut_a(trx_in_trx_list(lock->trx));
  1447. if (index) {
  1448. ut_a(lock->index == index);
  1449. }
  1450. if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) {
  1451. if (lock_get_mode(lock) == LOCK_S) {
  1452. ut_a(!lock_rec_other_has_expl_req(LOCK_X,
  1453. 0, 0, rec, lock->trx));
  1454. } else {
  1455. ut_a(!lock_rec_other_has_expl_req(LOCK_S,
  1456. 0, 0, rec, lock->trx));
  1457. }
  1458. } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
  1459. ut_a(lock_rec_has_to_wait_in_queue(lock));
  1460. }
  1461. lock = lock_rec_get_next(rec, lock);
  1462. }
  1463. lock_mutex_exit_kernel();
  1464. return(TRUE);
  1465. }
  1466. /*************************************************************************
  1467. Validates the record lock queues on a page. */
  1468. ibool
  1469. lock_rec_validate_page(
  1470. /*===================*/
  1471. /* out: TRUE if ok */
  1472. ulint space, /* in: space id */
  1473. ulint page_no)/* in: page number */
  1474. {
  1475. dict_index_t* index;
  1476. page_t* page;
  1477. lock_t* lock;
  1478. rec_t* rec;
  1479. ulint nth_lock = 0;
  1480. ulint nth_bit = 0;
  1481. ulint i;
  1482. mtr_t mtr;
  1483. #ifdef UNIV_SYNC_DEBUG
  1484. ut_ad(!mutex_own(&kernel_mutex));
  1485. #endif /* UNIV_SYNC_DEBUG */
  1486. mtr_start(&mtr);
  1487. page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);
  1488. #ifdef UNIV_SYNC_DEBUG
  1489. buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK);
  1490. #endif /* UNIV_SYNC_DEBUG */
  1491. lock_mutex_enter_kernel();
  1492. loop:
  1493. lock = lock_rec_get_first_on_page_addr(space, page_no);
  1494. if (!lock) {
  1495. goto function_exit;
  1496. }
  1497. for (i = 0; i < nth_lock; i++) {
  1498. lock = lock_rec_get_next_on_page(lock);
  1499. if (!lock) {
  1500. goto function_exit;
  1501. }
  1502. }
  1503. ut_a(trx_in_trx_list(lock->trx));
  1504. ut_a(lock->trx->conc_state == TRX_ACTIVE
  1505.      || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
  1506. for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
  1507. if (i == 1 || lock_rec_get_nth_bit(lock, i)) {
  1508. index = lock->index;
  1509. rec = page_find_rec_with_heap_no(page, i);
  1510. fprintf(stderr,
  1511. "Validating %lu %lun", (ulong) space, (ulong) page_no);
  1512. lock_mutex_exit_kernel();
  1513. lock_rec_queue_validate(rec, index);
  1514. lock_mutex_enter_kernel();
  1515. nth_bit = i + 1;
  1516. goto loop;
  1517. }
  1518. }
  1519. nth_bit = 0;
  1520. nth_lock++;
  1521. goto loop;
  1522. function_exit:
  1523. lock_mutex_exit_kernel();
  1524. mtr_commit(&mtr);
  1525. return(TRUE);
  1526. }
  1527. /*************************************************************************
  1528. Validates the lock system. */
  1529. ibool
  1530. lock_validate(void)
  1531. /*===============*/
  1532. /* out: TRUE if ok */
  1533. {
  1534. lock_t* lock;
  1535. trx_t* trx;
  1536. dulint limit;
  1537. ulint space;
  1538. ulint page_no;
  1539. ulint i;
  1540. lock_mutex_enter_kernel();
  1541. trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
  1542. while (trx) {
  1543. lock = UT_LIST_GET_FIRST(trx->trx_locks);
  1544. while (lock) {
  1545. if (lock_get_type(lock) & LOCK_TABLE) {
  1546. lock_table_queue_validate(
  1547. lock->un_member.tab_lock.table);
  1548. }
  1549. lock = UT_LIST_GET_NEXT(trx_locks, lock);
  1550. }
  1551. trx = UT_LIST_GET_NEXT(trx_list, trx);
  1552. }
  1553. for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
  1554. limit = ut_dulint_zero;
  1555. for (;;) {
  1556. lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
  1557. while (lock) {
  1558. ut_a(trx_in_trx_list(lock->trx));
  1559. space = lock->un_member.rec_lock.space;
  1560. page_no = lock->un_member.rec_lock.page_no;
  1561. if (ut_dulint_cmp(
  1562. ut_dulint_create(space, page_no),
  1563. limit) >= 0) {
  1564. break;
  1565. }
  1566. lock = HASH_GET_NEXT(hash, lock);
  1567. }
  1568. if (!lock) {
  1569. break;
  1570. }
  1571. lock_mutex_exit_kernel();
  1572. lock_rec_validate_page(space, page_no);
  1573. lock_mutex_enter_kernel();
  1574. limit = ut_dulint_create(space, page_no + 1);
  1575. }
  1576. }
  1577. lock_mutex_exit_kernel();
  1578. return(TRUE);
  1579. }
  1580. /*============ RECORD LOCK CHECKS FOR ROW OPERATIONS ====================*/
  1581. /*************************************************************************
  1582. Checks if locks of other transactions prevent an immediate insert of
  1583. a record. If they do, first tests if the query thread should anyway
  1584. be suspended for some reason; if not, then puts the transaction and
  1585. the query thread to the lock wait state and inserts a waiting request
  1586. for a gap x-lock to the lock queue. */
  1587. ulint
  1588. lock_rec_insert_check_and_lock(
  1589. /*===========================*/
  1590. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  1591. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  1592. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  1593. does nothing */
  1594. rec_t* rec, /* in: record after which to insert */
  1595. dict_index_t* index, /* in: index */
  1596. que_thr_t* thr, /* in: query thread */
  1597. ibool* inherit)/* out: set to TRUE if the new inserted
  1598. record maybe should inherit LOCK_GAP type
  1599. locks from the successor record */
  1600. {
  1601. rec_t* next_rec;
  1602. trx_t* trx;
  1603. lock_t* lock;
  1604. ulint err;
  1605. if (flags & BTR_NO_LOCKING_FLAG) {
  1606. return(DB_SUCCESS);
  1607. }
  1608. ut_ad(rec);
  1609. trx = thr_get_trx(thr);
  1610. next_rec = page_rec_get_next(rec);
  1611. *inherit = FALSE;
  1612. lock_mutex_enter_kernel();
  1613. ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
  1614. lock = lock_rec_get_first(next_rec);
  1615. if (lock == NULL) {
  1616. /* We optimize CPU time usage in the simplest case */
  1617. lock_mutex_exit_kernel();
  1618. if (!(index->type & DICT_CLUSTERED)) {
  1619. /* Update the page max trx id field */
  1620. page_update_max_trx_id(buf_frame_align(rec),
  1621. thr_get_trx(thr)->id);
  1622. }
  1623. return(DB_SUCCESS);
  1624. }
  1625. *inherit = TRUE;
  1626. /* If another transaction has an explicit lock request which locks
  1627. the gap, waiting or granted, on the successor, the insert has to wait.
  1628. An exception is the case where the lock by the another transaction
  1629. is a gap type lock which it placed to wait for its turn to insert. We
  1630. do not consider that kind of a lock conflicting with our insert. This
  1631. eliminates an unnecessary deadlock which resulted when 2 transactions
  1632. had to wait for their insert. Both had waiting gap type lock requests
  1633. on the successor, which produced an unnecessary deadlock. */
  1634. if (lock_rec_other_has_conflicting(LOCK_X | LOCK_GAP
  1635. | LOCK_INSERT_INTENTION, next_rec, trx)) {
  1636. /* Note that we may get DB_SUCCESS also here! */
  1637. err = lock_rec_enqueue_waiting(LOCK_X | LOCK_GAP
  1638. | LOCK_INSERT_INTENTION,
  1639. next_rec, index, thr);
  1640. } else {
  1641. err = DB_SUCCESS;
  1642. }
  1643. lock_mutex_exit_kernel();
  1644. if (!(index->type & DICT_CLUSTERED) && (err == DB_SUCCESS)) {
  1645. /* Update the page max trx id field */
  1646. page_update_max_trx_id(buf_frame_align(rec),
  1647. thr_get_trx(thr)->id);
  1648. }
  1649. ut_ad(lock_rec_queue_validate(next_rec, index));
  1650. return(err);
  1651. }
  1652. /*************************************************************************
  1653. If a transaction has an implicit x-lock on a record, but no explicit x-lock
  1654. set on the record, sets one for it. NOTE that in the case of a secondary
  1655. index, the kernel mutex may get temporarily released. */
  1656. static
  1657. void
  1658. lock_rec_convert_impl_to_expl(
  1659. /*==========================*/
  1660. rec_t* rec, /* in: user record on page */
  1661. dict_index_t* index) /* in: index of record */
  1662. {
  1663. trx_t* impl_trx;
  1664. #ifdef UNIV_SYNC_DEBUG
  1665. ut_ad(mutex_own(&kernel_mutex));
  1666. #endif /* UNIV_SYNC_DEBUG */
  1667. ut_ad(page_rec_is_user_rec(rec));
  1668. if (index->type & DICT_CLUSTERED) {
  1669. impl_trx = lock_clust_rec_some_has_impl(rec, index);
  1670. } else {
  1671. impl_trx = lock_sec_rec_some_has_impl_off_kernel(rec, index);
  1672. }
  1673. if (impl_trx) {
  1674. /* If the transaction has no explicit x-lock set on the
  1675. record, set one for it */
  1676. if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
  1677. impl_trx)) {
  1678. lock_rec_add_to_queue(LOCK_REC | LOCK_X
  1679.       | LOCK_REC_NOT_GAP, rec, index,
  1680. impl_trx);
  1681. }
  1682. }
  1683. }
  1684. /*************************************************************************
  1685. Checks if locks of other transactions prevent an immediate modify (update,
  1686. delete mark, or delete unmark) of a clustered index record. If they do,
  1687. first tests if the query thread should anyway be suspended for some
  1688. reason; if not, then puts the transaction and the query thread to the
  1689. lock wait state and inserts a waiting request for a record x-lock to the
  1690. lock queue. */
  1691. ulint
  1692. lock_clust_rec_modify_check_and_lock(
  1693. /*=================================*/
  1694. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  1695. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  1696. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  1697. does nothing */
  1698. rec_t* rec, /* in: record which should be modified */
  1699. dict_index_t* index, /* in: clustered index */
  1700. que_thr_t* thr) /* in: query thread */
  1701. {
  1702. ulint err;
  1703. if (flags & BTR_NO_LOCKING_FLAG) {
  1704. return(DB_SUCCESS);
  1705. }
  1706. ut_ad(index->type & DICT_CLUSTERED);
  1707. lock_mutex_enter_kernel();
  1708. ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
  1709. /* If a transaction has no explicit x-lock set on the record, set one
  1710. for it */
  1711. lock_rec_convert_impl_to_expl(rec, index);
  1712. err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, rec, index, thr);
  1713. lock_mutex_exit_kernel();
  1714. ut_ad(lock_rec_queue_validate(rec, index));
  1715. return(err);
  1716. }
  1717. /*************************************************************************
  1718. Checks if locks of other transactions prevent an immediate modify (delete
  1719. mark or delete unmark) of a secondary index record. */
  1720. ulint
  1721. lock_sec_rec_modify_check_and_lock(
  1722. /*===============================*/
  1723. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  1724. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  1725. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  1726. does nothing */
  1727. rec_t* rec, /* in: record which should be modified;
  1728. NOTE: as this is a secondary index, we
  1729. always have to modify the clustered index
  1730. record first: see the comment below */
  1731. dict_index_t* index, /* in: secondary index */
  1732. que_thr_t* thr) /* in: query thread */
  1733. {
  1734. ulint err;
  1735. if (flags & BTR_NO_LOCKING_FLAG) {
  1736. return(DB_SUCCESS);
  1737. }
  1738. ut_ad(!(index->type & DICT_CLUSTERED));
  1739. /* Another transaction cannot have an implicit lock on the record,
  1740. because when we come here, we already have modified the clustered
  1741. index record, and this would not have been possible if another active
  1742. transaction had modified this secondary index record. */
  1743. lock_mutex_enter_kernel();
  1744. ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
  1745. err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, rec, index, thr);
  1746. lock_mutex_exit_kernel();
  1747. ut_ad(lock_rec_queue_validate(rec, index));
  1748. if (err == DB_SUCCESS) {
  1749. /* Update the page max trx id field */
  1750. page_update_max_trx_id(buf_frame_align(rec),
  1751. thr_get_trx(thr)->id);
  1752. }
  1753. return(err);
  1754. }
  1755. /*************************************************************************
  1756. Like the counterpart for a clustered index below, but now we read a
  1757. secondary index record. */
  1758. ulint
  1759. lock_sec_rec_read_check_and_lock(
  1760. /*=============================*/
  1761. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  1762. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  1763. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  1764. does nothing */
  1765. rec_t* rec, /* in: user record or page supremum record
  1766. which should be read or passed over by a read
  1767. cursor */
  1768. dict_index_t* index, /* in: secondary index */
  1769. ulint mode, /* in: mode of the lock which the read cursor
  1770. should set on records: LOCK_S or LOCK_X; the
  1771. latter is possible in SELECT FOR UPDATE */
  1772. ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
  1773. LOCK_REC_NOT_GAP */
  1774. que_thr_t* thr) /* in: query thread */
  1775. {
  1776. ulint err;
  1777. ut_ad(!(index->type & DICT_CLUSTERED));
  1778. ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
  1779. if (flags & BTR_NO_LOCKING_FLAG) {
  1780. return(DB_SUCCESS);
  1781. }
  1782. lock_mutex_enter_kernel();
  1783. ut_ad(mode != LOCK_X
  1784.       || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
  1785. ut_ad(mode != LOCK_S
  1786.       || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
  1787. /* Some transaction may have an implicit x-lock on the record only
  1788. if the max trx id for the page >= min trx id for the trx list or a
  1789. database recovery is running. */
  1790. if (((ut_dulint_cmp(page_get_max_trx_id(buf_frame_align(rec)),
  1791. trx_list_get_min_trx_id()) >= 0)
  1792.       || recv_recovery_is_on())
  1793.      && !page_rec_is_supremum(rec)) {
  1794.   lock_rec_convert_impl_to_expl(rec, index);
  1795. }
  1796. err = lock_rec_lock(FALSE, mode | gap_mode, rec, index, thr);
  1797. lock_mutex_exit_kernel();
  1798. ut_ad(lock_rec_queue_validate(rec, index));
  1799. return(err);
  1800. }
  1801. /*************************************************************************
  1802. Checks if locks of other transactions prevent an immediate read, or passing
  1803. over by a read cursor, of a clustered index record. If they do, first tests
  1804. if the query thread should anyway be suspended for some reason; if not, then
  1805. puts the transaction and the query thread to the lock wait state and inserts a
  1806. waiting request for a record lock to the lock queue. Sets the requested mode
  1807. lock on the record. */
  1808. ulint
  1809. lock_clust_rec_read_check_and_lock(
  1810. /*===============================*/
  1811. /* out: DB_SUCCESS, DB_LOCK_WAIT,
  1812. DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
  1813. ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
  1814. does nothing */
  1815. rec_t* rec, /* in: user record or page supremum record
  1816. which should be read or passed over by a read
  1817. cursor */
  1818. dict_index_t* index, /* in: clustered index */
  1819. ulint mode, /* in: mode of the lock which the read cursor
  1820. should set on records: LOCK_S or LOCK_X; the
  1821. latter is possible in SELECT FOR UPDATE */
  1822. ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
  1823. LOCK_REC_NOT_GAP */
  1824. que_thr_t* thr) /* in: query thread */
  1825. {
  1826. ulint err;
  1827. ut_ad(index->type & DICT_CLUSTERED);
  1828. ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
  1829. ut_ad(gap_mode == LOCK_ORDINARY || gap_mode == LOCK_GAP
  1830. || gap_mode == LOCK_REC_NOT_GAP);
  1831. if (flags & BTR_NO_LOCKING_FLAG) {
  1832. return(DB_SUCCESS);
  1833. }
  1834. lock_mutex_enter_kernel();
  1835. ut_ad(mode != LOCK_X
  1836.       || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
  1837. ut_ad(mode != LOCK_S
  1838.       || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
  1839. if (!page_rec_is_supremum(rec)) {
  1840.       
  1841. lock_rec_convert_impl_to_expl(rec, index);
  1842. }
  1843. err = lock_rec_lock(FALSE, mode | gap_mode, rec, index, thr);
  1844. lock_mutex_exit_kernel();
  1845. ut_ad(lock_rec_queue_validate(rec, index));
  1846. return(err);
  1847. }