Deadlock case four

Source: public account yangyidba

A , foreword
deadlock, in fact, is a very interesting technical problem is also very challenging, probably each part of the development and DBA students will meet in the course of their work. Regarding deadlock, I will continue to write a series of case studies, hoping to help friends who want to understand deadlock. This article introduces an example of deadlock caused by three concurrent inserts. The root cause is that the unique key of the insert applies for the special GAP lock of the insertion intention lock. In fact, it is more reasonable to call Insert Intention Gap Lock.

2. Case analysis
2.1 Environment preparation 
Percona server 5.6 RR mode

  1. CREATE TABLE `t6` (

  2.   `id` int(11) NOT NULL AUTO_INCREMENT,

  3.   `a` int(11) DEFAULT NULL,

  4.   PRIMARY KEY (`id`),

  5.   unique KEY `idx_a` (`a`)

  6. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

  7. insert into t6 values(1,2),(2,8),(3,9),(4,11),(5,19)

sess1

sess2

sess3

begin;



insert into t6(id,a) values(6,15);

begin;



insert into t6(id,a) values(7,15);

begin;



insert into t6(id,a) values(8,15);

rollback; 


ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction


2.2 Deadlock log

  1. ------------------------

  2. LATEST DETECTED DEADLOCK

  3. ------------------------

  4. 2017-09-18 10:03:50 7f78eae30700

  5. *** (1) TRANSACTION:

  6. TRANSACTION 462308725, ACTIVE 18 sec inserting, thread declared inside InnoDB 1

  7. mysql tables in use 1, locked 1

  8. LOCK WAIT 4 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 1

  9. MySQL thread id 3825465, OS thread handle 0x7f78eaef4700, query id 781148519 localhost root update

  10. insert into t6(id,a) values(7,15)

  11. *** (1) WAITING FOR THIS LOCK TO BE GRANTED:

  12. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308725 lock_mode X insert intention waiting

  13. *** (2) TRANSACTION:

  14. TRANSACTION 462308726, ACTIVE 10 sec inserting, thread declared inside InnoDB 1

  15. mysql tables in use 1, locked 1

  16. 4 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 1

  17. MySQL thread id 3825581, OS thread handle 0x7f78eae30700, query id 781148528 localhost root update

  18. insert into t6(id,a) values(8,15)

  19. *** (2) HOLDS THE LOCK(S):

  20. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308726 lock mode S

  21. *** (2) WAITING FOR THIS LOCK TO BE GRANTED:

  22. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308726 lock_mode X insert intention waiting

  23. *** WE ROLL BACK TRANSACTION (2)

2.3 Deadlock analysis
First of all, we still need to re-emphasize the locking logic of insert operation.

The first stage: uniqueness constraint check, first apply for LOCK_S + LOCK_ORDINARY.
Second stage:  acquire the lock of stage one and insert successfully, the insert position has a gap lock: LOCK_INSERT_INTENTION, in order to prevent other insert unique key conflicts.
New data insertion: LOCK_X + LOCK_REC_NOT_GAP
For the insert operation, if a unique constraint conflict occurs, you need to add S Next-key Lock to the conflicting unique index. From here, you will find that even at the RC transaction isolation level, there will also be a Next-Key Lock lock, thereby blocking concurrency. However, what the document does not say is that for the unique index where the conflict is detected, the waiting thread needs to lock the next record after obtaining the S Lock. The source code is judged by the function row_ins_scan_sec_index_for_duplicate.

Secondly, we need the unlocked compatibility matrix.

From the compatibility matrix, we can draw the following conclusions:

  1. There will be no conflicts between INSERT operations.

  2. GAP, Next-Key will block Insert.

  3. GAP and Record, Next-Key will not conflict

  4. Record and Record, Next-Key conflict with each other.

  5. The existing Insert lock does not prevent any locks to be added.

In this case, three sessions are executed concurrently. I plan to analyze the transaction log after each step is executed step by step.

The first step, sess1 performs the insert operation

insert into t6(id,a) values(6,15);

  1. ---TRANSACTION 462308737, ACTIVE 5 sec

  2. 1 lock struct(s), heap size 360, 0 row lock(s), undo log entries 1

  3. MySQL thread id 3825779, OS thread handle 0x7f78eacd9700, query id 781149440 localhost root init

  4. show engine innodb status

  5. TABLE LOCK table `test`.`t6` trx id 462308737 lock mode IX

Because of the first inserted statement, the uniqueness conflict check passed and the insertion was successful (6,15). At this time, the sess1 session holds the LOCK_X|LOCK_REC_NOT_GAP lock of (6,15). Refer to "INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a next-key lock (that is, there is no gap lock) and does not prevent other sessions from inserting into the gap before the inserted row." The

second step, sess2 performs an insert operation
insert into t6(id,a) values(7,15);

  1. ---TRANSACTION 462308738, ACTIVE 4 sec inserting

  2. mysql tables in use 1, locked 1

  3. LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1

  4. MySQL thread id 3825768, OS thread handle 0x7f78ea9c9700, query id 781149521 localhost root update

  5. insert into t6(id,a) values(7,15)

  6. ------- TRX HAS BEEN WAITING 4 SEC FOR THIS LOCK TO BE GRANTED:

  7. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S waiting

  8. ------------------

  9. TABLE LOCK table `test`.`t6` trx id 462308738 lock mode IX

  10. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S waiting

  11. ---TRANSACTION 462308737, ACTIVE 66 sec

  12. 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1

  13. MySQL thread id 3825779, OS thread handle 0x7f78eacd9700, query id 781149526 localhost root init

  14. show engine innodb status

  15. TABLE LOCK table `test`.`t6` trx id 462308737 lock mode IX

  16. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308737 lock_mode X locks rec but not gap

First, sess2's insert applies for an IX lock, because the sess1 session has been inserted successfully and holds the X row lock with the unique key a=15, so sess2 insert performs the uniqueness check, first apply for LOCK_S + LOCK_ORDINARY, and the transaction log list prompts lock mode S waiting


The third step, sess3 performs an insert operation
insert into t6(id,a) values(8,15);

  1. ---TRANSACTION 462308739, ACTIVE 3 sec inserting

  2. mysql tables in use 1, locked 1

  3. LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1

  4. MySQL thread id 3825764, OS thread handle 0x7f78ea593700, query id 781149555 localhost root update

  5. insert into t6(id,a) values(8,15)

  6. ------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:

  7. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308739 lock mode S waiting

  8. ------------------

  9. TABLE LOCK table `test`.`t6` trx id 462308739 lock mode IX

  10. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308739 lock mode S waiting

  11. ---TRANSACTION 462308738, ACTIVE 35 sec inserting

  12. mysql tables in use 1, locked 1

  13. LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1

  14. MySQL thread id 3825768, OS thread handle 0x7f78ea9c9700, query id 781149521 localhost root update

  15. insert into t6(id,a) values(7,15)

  16. ------- TRX HAS BEEN WAITING 35 SEC FOR THIS LOCK TO BE GRANTED:

  17. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S waiting

  18. ------------------

  19. TABLE LOCK table `test`.`t6` trx id 462308738 lock mode IX

  20. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S waiting

  21. ---TRANSACTION 462308737, ACTIVE 97 sec

  22. 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1

  23. MySQL thread id 3825779, OS thread handle 0x7f78eacd9700, query id 781149560 localhost root init

  24. show engine innodb status

  25. TABLE LOCK table `test`.`t6` trx id 462308737 lock mode IX

  26. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308737 lock_mode X locks rec but not gap

It is consistent with the lock application process of session sess2, all of which are waiting for sess1 to release the lock resources.

The fourth step sess1 performs a rollback operation, sess2 does not commit

sess1 rollback;
At this time, sess2 is inserted successfully and sess3 is deadlocked. At this time, sess2 insert is inserted successfully and has not yet been submitted. The transaction list is as follows:

  1. ------------

  2. TRANSACTIONS

  3. ------------

  4. Trx id counter 462308744

  5. Purge done for trx s n:o < 462308744 undo n:o < 0 state: running but idle

  6. History list length 1866

  7. LIST OF TRANSACTIONS FOR EACH SESSION:

  8. ---TRANSACTION 462308737, not started

  9. MySQL thread id 3825779, OS thread handle 0x7f78eacd9700, query id 781149626 localhost root init

  10. show engine innodb status

  11. ---TRANSACTION 462308739, not started

  12. MySQL thread id 3825764, OS thread handle 0x7f78ea593700, query id 781149555 localhost root cleaning up

  13. ---TRANSACTION 462308738, ACTIVE 75 sec

  14. 5 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1

  15. MySQL thread id 3825768, OS thread handle 0x7f78eadce700, query id 781149608 localhost root cleaning up

  16. TABLE LOCK table `test`.`t6` trx id 462308738 lock mode IX

  17. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S

  18. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S

  19. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock_mode X insert intention

  20. RECORD LOCKS space id 227 page no 4 n bits 80 index `idx_a` of table `test`.`t6` trx id 462308738 lock mode S locks gap before rec

Three, the cause of deadlock

  • sess1 insert is successful and X lock is added to the unique key of a=15.

  • sess2 executes insert (6,15), and performs uniqueness check before inserting. It is found that the duplicate key of the inserted record of sess1 needs to apply for LOCK_S|LOCK_ORDINARY, but it conflicts with sess1's (LOCK_X | LOCK_REC_NOT_GAP), join the waiting queue and wait for sess1 Release the lock.

  • sess3 executes insert (7,15), and performs uniqueness check before inserting. It is found that the duplicate key with the inserted record of sess1 needs to apply for LOCK_S|LOCK_ORDINARY, but it conflicts with (LOCK_X | LOCK_REC_NOT_GAP) of sess1, join the waiting queue and wait for sess1 Release the lock.

  • sess1 executes a rollback, sess1 releases the exclusive record lock (LOCK_X | LOCK_REC_NOT_GAP) on index a=15, and then sess2 and sess3 obtain the S lock (LOCK_S|LOCK_ORDINARY) successfully, sess2 and sess3 both request the exclusive record lock on index a=15 (LOCK_X | LOCK_REC_NOT_GAP), the log prompts lock_mode X insert intention. Since X lock and S lock are mutually exclusive, sess2 and sess3 both wait for each other to release S lock, so a deadlock occurs, and MySQL chooses to roll back one of them.

Four, summary

Deadlock analysis is already very challenging, especially for insert unique key conflicts, which need to be applied in multiple stages and understand the compatibility matrix of locks. For this piece of knowledge I need to learn and understand, this article can be regarded as an introduction. If there is any incorrect analysis and understanding, please correct me.

Extended reading

The full text is over.

Enjoy MySQL :)



Teacher Ye's "MySQL Core Optimization" class has been upgraded to MySQL 8.0, scan the code to start the journey of MySQL 8.0 practice

Guess you like

Origin blog.csdn.net/n88Lpo/article/details/108459083