From 18674328782861e73449f3bb7cf375a685dca822 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= <jan.lindstrom@galeracluster.com>
Date: Thu, 30 Mar 2023 12:14:15 +0300
Subject: [PATCH] MDEV-30963 : Assertion failure
 !lock.was_chosen_as_deadlock_victim in trx0trx.h:1065

Race condition between trx_t::commit_cleanup() on transaction that
has empty write set and MDL BF-kill.

DBUG_SYNC point and test case to reproduce crash.
---
 .../suite/galera/t/galera_bf_kill_empty.test  | 48 +++++++++++++++++++
 storage/innobase/trx/trx0trx.cc               | 12 +++++
 2 files changed, 60 insertions(+)
 create mode 100644 mysql-test/suite/galera/t/galera_bf_kill_empty.test

diff --git a/mysql-test/suite/galera/t/galera_bf_kill_empty.test b/mysql-test/suite/galera/t/galera_bf_kill_empty.test
new file mode 100644
index 00000000000..2769c8f464e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_kill_empty.test
@@ -0,0 +1,48 @@
+--source include/galera_cluster.inc
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1
+create table t1(a int not null primary key, b int) engine=innodb;
+insert into t1 values (1,1),(2,2),(3,3),(4,4);
+
+--connection node_1
+# Pause delete before inside trx_t::commit() before trx_t::commit_cleanup()
+SET SESSION debug_dbug = '+d,sync.wsrep_trx_commit';
+--send delete from t1 where a = 7;
+
+# Wait until delete reaches sync point
+--connection node_1a
+SET SESSION DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_trx_commit_reached';
+
+--connection node_1b
+#
+# Send conflicting operation to same table we will find MDL-conflict
+#
+SET SESSION debug_dbug = '+d,sync.wsrep_before_wsrep_thd_abort';
+--send OPTIMIZE TABLE t1;
+
+--connection node_1a
+# Wait for BF to set victim mark, we try to BF-abort
+# delete but as we are already TRX_STATE_COMMITTED_IN_MEMORY
+# we can't and it will lead crash as trx_t::lock.was_chosen_as_deadlock_victim
+# is true.
+SET SESSION DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_before_wsrep_thd_abort_reached';
+
+# Release delete to continue
+SET SESSION DEBUG_SYNC = 'now SIGNAL signal.wsrep_after_run_commit_hooks';
+# Release optimize table
+SET SESSION DEBUG_SYNC = 'now SIGNAL signal.wsrep_before_wsrep_thd_abort';
+SET SESSION DEBUG_SYNC = 'RESET';
+SET GLOBAL debug_dbug = "";
+
+--connection node_1
+--error 0,ER_LOCK_DEADLOCK
+--reap
+
+--connection node_1b
+--reap
+
+drop table t1;
+
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index d7ab02844bf..8b47b206a81 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -48,6 +48,7 @@ Created 3/26/1996 Heikki Tuuri
 #include "ut0pool.h"
 #include "ut0vec.h"
 #include "log.h"
+#include "debug_sync.h"         // DEBUG_SYNC
 
 #include <set>
 #include <new>
@@ -1478,6 +1479,17 @@ void trx_t::commit()
   commit_persist();
   ut_d(was_dict_operation= false);
   ut_d(for (const auto &p : mod_tables) ut_ad(!p.second.is_dropped()));
+#ifdef WITH_WSREP
+  DBUG_EXECUTE_IF("sync.wsrep_trx_commit",
+  {
+    const char act[]=
+      "now "
+      "SIGNAL sync.wsrep_trx_commit_reached "
+      "WAIT_FOR signal.wsrep_trx_commit";
+      DBUG_ASSERT(!debug_sync_set_action(mysql_thd,
+                                         STRING_WITH_LEN(act)));
+  };);
+#endif /* WITH_WSREP */
   commit_cleanup();
 }
 
-- 
2.37.2

