|
| 1 | +--source include/have_innodb.inc |
| 2 | +--source include/count_sessions.inc |
| 3 | + |
| 4 | +CREATE TABLE t1 ( |
| 5 | + pkey int NOT NULL PRIMARY KEY, |
| 6 | + c int |
| 7 | +) ENGINE=InnoDB; |
| 8 | + |
| 9 | +INSERT INTO t1 VALUES(1,1); |
| 10 | + |
| 11 | +CREATE TABLE t2 ( |
| 12 | + pkey int NOT NULL PRIMARY KEY, |
| 13 | + c int |
| 14 | +) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
| 15 | + |
| 16 | +INSERT INTO t2 VALUES (2, NULL); |
| 17 | + |
| 18 | +# The following table is to increase tansaction weight on deadlock resolution |
| 19 | +CREATE TABLE t3 (c int) engine = InnoDB; |
| 20 | +INSERT INTO t3 VALUES (10), (20), (30), (40), (50); |
| 21 | + |
| 22 | +--let $i= 2 |
| 23 | +--let $delete= 2 |
| 24 | +--let $update= 1 |
| 25 | +--connect(con1, localhost,root,,) |
| 26 | + |
| 27 | +while($i) { |
| 28 | +--connection default |
| 29 | +START TRANSACTION; # trx 1 |
| 30 | +# The following update is necessary to increase the transaction weight, which is |
| 31 | +# calculated as the number of locks + the number of undo records during deadlock |
| 32 | +# report. Victim's transaction should have minimum weight. We need trx 2 to be |
| 33 | +# choosen as victim, that's why we need to increase the current transaction |
| 34 | +# weight. |
| 35 | +UPDATE t3 SET c=c+1000; |
| 36 | +SELECT * FROM t1 FOR UPDATE; |
| 37 | + |
| 38 | +--connection con1 |
| 39 | +START TRANSACTION; # trx 2 |
| 40 | +# 1) read record from t2, lock it |
| 41 | +# 2) check if the read record should be deleted, i.e. read record from t1, |
| 42 | +# as the record from t1 is locked by trx 1, the subselect will be suspended. |
| 43 | +# see 'while' loop in mysql_delete() or mysql_update() and |
| 44 | +# select->skip_record(thd) call for details. |
| 45 | +if ($i == $delete) { |
| 46 | +--send DELETE FROM t2 WHERE c NOT IN (SELECT ref_0.pkey FROM t1 AS ref_0 INNER JOIN t1 AS ref_1 ON ref_0.c = ref_0.pkey) |
| 47 | +} |
| 48 | +if ($i == $update) { |
| 49 | +--send UPDATE t2 SET pkey=pkey+10 WHERE c NOT IN (SELECT ref_0.pkey FROM t1 AS ref_0 INNER JOIN t1 AS ref_1 ON ref_0.c = ref_0.pkey) |
| 50 | +} |
| 51 | + |
| 52 | +--connection default |
| 53 | +let $wait_condition= |
| 54 | + SELECT count(*) = 1 FROM information_schema.processlist |
| 55 | + WHERE (state = 'Sending data' OR state = "Updating") |
| 56 | + AND (info LIKE 'delete from t2 where%' OR |
| 57 | + info LIKE 'UPDATE t2 SET pkey=pkey+10 WHERE%'); |
| 58 | +--source include/wait_condition.inc |
| 59 | + |
| 60 | +# The record from t2 is locked by the previous delete, so trx 2 is waiting for |
| 61 | +# trx 1, and trx 1 will be blocked by trx 2 with the following SELECT. So we |
| 62 | +# have deadlock here. And trx 2 is chosen as deadlock victim as trx 1 has |
| 63 | +# greater weight. |
| 64 | +SELECT * FROM t2 FOR UPDATE; |
| 65 | +COMMIT; |
| 66 | + |
| 67 | +--connection con1 |
| 68 | +# If the bug is not fixed, there will be assertion failure as |
| 69 | +# mysql_delete()/mysql_update() will continue execution despite its subselect |
| 70 | +# got deadlock error |
| 71 | +--error ER_LOCK_DEADLOCK |
| 72 | +--reap |
| 73 | +COMMIT; |
| 74 | +--dec $i |
| 75 | +} |
| 76 | + |
| 77 | +--disconnect con1 |
| 78 | + |
| 79 | +--connection default |
| 80 | +DROP TABLE t1,t2,t3; |
| 81 | +--source include/wait_until_count_sessions.inc |
0 commit comments