commit 94e2ea663de8ccabfde1fb3d26b2191f5fe5c4fe (HEAD -> 10.6, origin/knielsen_mdev32096)
Author: Kristian Nielsen <knielsen@knielsen-hq.org>
Date:   Tue Sep 5 13:00:28 2023 +0200

    MDEV-32096: Ugly testcase reproducing lost deadlock kill and hanging optimistic parallel replication
    
    Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>

diff --git a/mysql-test/suite/rpl/t/rpl_parallel_mdev32096_b.test b/mysql-test/suite/rpl/t/rpl_parallel_mdev32096_b.test
new file mode 100644
index 00000000000..4417f5ef610
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_mdev32096_b.test
@@ -0,0 +1,79 @@
+--source include/have_innodb.inc
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--connection slave
+--source include/stop_slave.inc
+SET @old_parallel= @@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads= 3;
+SET @old_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode= optimistic;
+SET @old_timeout= @@GLOBAL.innodb_lock_wait_timeout;
+SET GLOBAL innodb_lock_wait_timeout=10;
+--source include/start_slave.inc
+
+--connection master
+
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0), (10, 0);
+
+--sync_slave_with_master
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,inject_mdev32096";
+
+--connection master
+# T1
+SET SESSION gtid_seq_no= 100;
+UPDATE t1 SET b=1 WHERE a=1;
+
+# T2
+SET SESSION gtid_seq_no= 101;
+BEGIN;
+UPDATE t1 SET b=2 WHERE a=6;
+UPDATE t1 SET b=2 WHERE a=7;
+#UPDATE t1 SET b=2 WHERE a=8;
+#UPDATE t1 SET b=2 WHERE a=9;
+#UPDATE t1 SET b=2 WHERE a=10;
+COMMIT;
+
+# T3
+SET SESSION gtid_seq_no= 102;
+BEGIN;
+UPDATE t1 SET b=3 WHERE a=1;
+UPDATE t1 SET b=3 WHERE a=2;
+UPDATE t1 SET b=3 WHERE a=3;
+UPDATE t1 SET b=3 WHERE a=4;
+UPDATE t1 SET b=3 WHERE a=5;
+UPDATE t1 SET b=3 WHERE a=6;
+UPDATE t1 SET b=3 WHERE a=7;
+UPDATE t1 SET b=3 WHERE a=8;
+UPDATE t1 SET b=3 WHERE a=9;
+UPDATE t1 SET b=3 WHERE a=10;
+COMMIT;
+
+SELECT * FROM t1 ORDER BY a;
+
+--save_master_pos
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+SET GLOBAL debug_dbug=@old_dbug;
+SELECT * FROM t1 ORDER BY a;
+
+# Cleanup.
+
+--connection slave
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_mode= @old_mode;
+SET GLOBAL slave_parallel_threads= @old_parallel;
+SET GLOBAL innodb_lock_wait_timeout= @old_timeout;
+--source include/start_slave.inc
+
+--connection master
+DROP TABLE t1;
+--source include/rpl_end.inc
+
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index c044defd000..acb1662e279 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1374,6 +1374,13 @@ handle_rpl_parallel_thread(void *arg)
         unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry,
                             &did_enter_cond, &old_stage);
 
+        DBUG_EXECUTE_IF("inject_mdev32096",
+        {
+          if (rgi->current_gtid.seq_no==100)
+            my_sleep(1000000);
+          if (rgi->current_gtid.seq_no==102)
+            my_sleep(500000);
+        });
         thd->wait_for_commit_ptr= &rgi->commit_orderer;
 
         if (opt_gtid_ignore_duplicates &&
@@ -1491,6 +1498,10 @@ handle_rpl_parallel_thread(void *arg)
                           if ((rgi->current_gtid.seq_no % 1000) == 0)
                             max_retries= 0;
                           );
+          DBUG_EXECUTE_IF("inject_mdev32096",
+                          if (rgi->current_gtid.seq_no == 100)
+                            max_retries= 0;
+                          );
           if (has_temporary_error(thd) && max_retries > 0)
             err= retry_event_group(rgi, rpt, qev);
         }
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index d1d264a7e8a..a08ec0ca970 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -1345,6 +1345,10 @@ sel_set_rec_lock(
 	block = btr_pcur_get_block(pcur);
 
 	trx = thr_get_trx(thr);
+        // ToDo: For some reason this doesn't work if done under
+        // DBUG_EXECUTE_IF("inject_mdev32096", ...) ?
+        if (trx->undo_no == 5)
+          my_sleep(1000000);
 
 	if (UT_LIST_GET_LEN(trx->lock.trx_locks) > 10000
 	    && buf_pool.running_out()) {
