diff --git a/mysql-test/suite/galera/r/MDEV-33136.result b/mysql-test/suite/galera/r/MDEV-33136.result new file mode 100644 index 00000000000..36159fa05cd --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-33136.result @@ -0,0 +1,21 @@ +connection node_2; +connection node_1; +connect node_1a,127.0.0.1,root,,test,$NODE_MYPORT_1; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +connection node_1a; +TRUNCATE TABLE t1; +SET SESSION wsrep_retry_autocommit = 0; +SET DEBUG_SYNC = 'dict_stats_mdl_acquired SIGNAL may_toi WAIT_FOR bf_abort'; +INSERT INTO t1 VALUES (1); +connection node_1; +SET DEBUG_SYNC = 'now WAIT_FOR may_toi'; +TRUNCATE TABLE t1; +connection node_1a; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1; +disconnect node_1a; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/MDEV-33136.test b/mysql-test/suite/galera/t/MDEV-33136.test new file mode 100644 index 00000000000..12765ef6dfb --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-33136.test @@ -0,0 +1,44 @@ +# +# MDEV-33136: Properly BF-abort user transactions with explicit locks +# +# User transactions may acquire explicit MDL locks from InnoDB level +# when persistent statistics is re-read for a table. +# If such a transaction would be subject to BF-abort, it was improperly +# detected as a system transaction and wouldn't get aborted. +# +# The fix: Check if a transaction holding explicit MDL locks is a user +# transaction in the MDL conflict handling code. + +--source include/galera_cluster.inc +--source include/have_debug_sync.inc +--source include/have_debug.inc + +--connect node_1a,127.0.0.1,root,,test,$NODE_MYPORT_1 + +--connection node_1 +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; + +--connection node_1a +TRUNCATE TABLE t1; +# TRUNCATE forces the next statement to re-read statistics from persistent storage, +# which will acquire MDL locks on the statistics tables in InnoDB. +SET SESSION wsrep_retry_autocommit = 0; +SET DEBUG_SYNC = 'dict_stats_mdl_acquired SIGNAL may_toi WAIT_FOR bf_abort'; +--send + INSERT INTO t1 VALUES (1); + +--connection node_1 +SET DEBUG_SYNC = 'now WAIT_FOR may_toi'; +TRUNCATE TABLE t1; + +--connection node_1a +# Local INSERT gets aborted. +--error ER_LOCK_DEADLOCK +--reap + +# Cleanup +--connection node_1 +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1; +--disconnect node_1a +--source include/galera_end.inc diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index b77cf66f6c1..6d20f60b290 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -3168,7 +3168,9 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx, } } else if (granted_thd->lex->sql_command == SQLCOM_FLUSH || - granted_thd->mdl_context.has_explicit_locks()) + /* System transactions with explicit locks are BACKUP. */ + (granted_thd->system_thread != NON_SYSTEM_THREAD && + granted_thd->mdl_context.has_explicit_locks())) { WSREP_DEBUG("BF thread waiting for FLUSH"); ticket->wsrep_report(wsrep_debug); diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index b54b66c251b..3d931c4a490 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -3865,6 +3865,10 @@ release_and_exit: goto release_and_exit; } +#ifdef ENABLED_DEBUG_SYNC + DEBUG_SYNC(thd, "dict_stats_mdl_acquired"); +#endif /* ENABLED_DEBUG_SYNC */ + trx = trx_create(); trx_start_internal_read_only(trx);