connect stop_purge,localhost,root; START TRANSACTION WITH CONSISTENT SNAPSHOT; connect con1,localhost,root,,; connect con2,localhost,root,,; connect con3,localhost,root,,; connection default; CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=0; INSERT INTO t1 (id) VALUES (1); # Simplest scenario: # , # , , # Before MDEV-34877: # , , # After MDEV-34877: # , , # Expected: instead of deadlocking, the con1's request should ignore con2's connection con1; BEGIN; SELECT * FROM t1 LOCK IN SHARE MODE; id 1 connection con2; BEGIN; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con2_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con2_will_wait'; SELECT * FROM t1 FOR UPDATE; id 1 COMMIT; connection con2; id 1 COMMIT; # The scenario when we bypass X<-S pair: # , # , , # , , # , , , connection con1; BEGIN; SELECT * FROM t1 LOCK IN SHARE MODE; id 1 connection con2; BEGIN; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con2_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con3; SET DEBUG_SYNC = 'now WAIT_FOR con2_will_wait'; BEGIN; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con3_will_wait'; SELECT * FROM t1 LOCK IN SHARE MODE;; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con3_will_wait'; SELECT * FROM t1 FOR UPDATE; id 1 COMMIT; connection con2; id 1 COMMIT; connection con3; id 1 COMMIT; # A variant of the above scenario: # , # , , # , , # Expected: a deadlock, as INSERT INTENTION should not overtake locks on gap, to not slice them connection con1; BEGIN; SELECT * FROM t1 WHERE id=1 FOR UPDATE; id 1 connection con2; BEGIN; SET DEBUG_SYNC = 'lock_wait_start SIGNAL con2_will_wait'; SELECT * FROM t1 LOCK IN SHARE MODE; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con2_will_wait'; INSERT INTO t1 VALUES (0); ROLLBACK; connection con2; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction COMMIT; # More complicated scenario: # , # , , # , , # , , , # , , # Expected: a deadlock, as INSERT INTENTION should not overtake locks on gap, to not slice them connection con1; BEGIN; SELECT * FROM t1 LOCK IN SHARE MODE; id 1 connection con2; BEGIN; SELECT * FROM t1 WHERE id=1 LOCK IN SHARE MODE; id 1 connection con3; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con3_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con3_will_wait'; SET DEBUG_SYNC = 'lock_wait_start SIGNAL con1_will_wait'; INSERT INTO t1 VALUES (0); connection con2; SET DEBUG_SYNC = 'now WAIT_FOR con1_will_wait'; COMMIT; connection con1; ROLLBACK; connection con3; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction # More complicated scenario. # , # , , # , , # , , , # Before MDEV-34877: # , , # After MDEV-34877: # , , connection con1; BEGIN; SELECT * FROM t1 LOCK IN SHARE MODE; id 1 connection con2; BEGIN; SELECT * FROM t1 WHERE id=1 LOCK IN SHARE MODE; id 1 connection default; connection con3; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con3_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con3_will_wait'; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con1_will_wait'; SELECT * FROM t1 WHERE id=1 FOR UPDATE; connection con2; SET DEBUG_SYNC = 'now WAIT_FOR con1_will_wait'; COMMIT; connection con1; id 1 COMMIT; connection con3; id 1 COMMIT; # A scenario, where con1 has to bypass two transactions: # # # # Before MDEV-34877: # # After MDEV-34877: # connection con1; BEGIN; SELECT * FROM t1 LOCK IN SHARE MODE; id 1 connection con2; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con2_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con3; SET DEBUG_SYNC = 'now WAIT_FOR con2_will_wait'; SET DEBUG_SYNC = 'lock_wait_before_suspend SIGNAL con3_will_wait'; SELECT * FROM t1 FOR UPDATE; connection con1; SET DEBUG_SYNC = 'now WAIT_FOR con3_will_wait'; SELECT * FROM t1 WHERE id=1 FOR UPDATE; id 1 COMMIT; connection con2; id 1 COMMIT; connection con3; id 1 COMMIT; connection default; disconnect con1; disconnect con2; disconnect con3; disconnect stop_purge; DROP TABLE t1;