From fd0aff52ff297d24115face517e91d5a264c045f Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Tue, 6 Jan 2026 17:26:05 +0100 Subject: [PATCH] PXC-4799 : PXC member used for backups fails with Inconsistency when pending DDL clashes with FTRWL". Draft fix for local deadlock issue. Ensure that CREATE TABLE statement (and other DDL statements) acquires protection against Backup Lock first (i.e. IX lock on BACKUP_LOCK MDL singleton) and only then tries to acquire protection against Global Read Lock (i.e. IX lock on GLOBAL MDL singleton) and not vice versa. This allows to avoid deadlock which sometimes occured and resulted in CREATE TABLE failure with appropriate error when mydumper backup tool was run concurrently. This (as well as some other) backup tool does LOCK INSTANCE FOR BACKUP first (which acquires S lock on BACKUP_LOCK singleton) and then does FLUSH TABLES WITH READ LOCK (which acquires S lock on GLOBAL MDL singleton). Acquiring conflicting lock in opposite order is deadlock-prone. --- mysql-test/r/pxc4799.result | 22 +++++++++++++++++++ mysql-test/t/pxc4799.test | 43 +++++++++++++++++++++++++++++++++++++ sql/mdl.cc | 2 +- sql/mdl.h | 6 +++--- 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 mysql-test/r/pxc4799.result create mode 100644 mysql-test/t/pxc4799.test diff --git a/mysql-test/r/pxc4799.result b/mysql-test/r/pxc4799.result new file mode 100644 index 000000000000..056dfb146b2d --- /dev/null +++ b/mysql-test/r/pxc4799.result @@ -0,0 +1,22 @@ +# +# PXC-4799 : "PXC member used for backups fails with Inconsistency +# when pending DDL clashes with FTRWL" - single node test. +# +connect con1, localhost, root,,; +connection default; +LOCK INSTANCE FOR BACKUP; +connection con1; +CREATE TABLE t1 (a INT); +connection default; +FLUSH TABLES WITH READ LOCK; +UNLOCK TABLES; +UNLOCK INSTANCE; +connection con1; +# Reap result of CREATE TABLE t1 +# +# Without the patch the CREAT TABLE statement would failed with +# ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction +# Clean up. +DROP TABLE t1; +disconnect con1; +connection default; diff --git a/mysql-test/t/pxc4799.test b/mysql-test/t/pxc4799.test new file mode 100644 index 000000000000..86e539808f5f --- /dev/null +++ b/mysql-test/t/pxc4799.test @@ -0,0 +1,43 @@ +--echo # +--echo # PXC-4799 : "PXC member used for backups fails with Inconsistency +--echo # when pending DDL clashes with FTRWL" - single node test. +--echo # + + +--enable_connect_log + +--connect (con1, localhost, root,,) +let $con1_id= `SELECT CONNECTION_ID()`; + +--connection default +LOCK INSTANCE FOR BACKUP; + +--connection con1 +--send CREATE TABLE t1 (a INT) + +--connection default +let $wait_condition= + SELECT count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE state = "Waiting for backup lock" AND id = $con1_id; +--source include/wait_condition.inc + +FLUSH TABLES WITH READ LOCK; + +UNLOCK TABLES; +UNLOCK INSTANCE; + +--connection con1 +--echo # Reap result of CREATE TABLE t1 +--echo # +--echo # Without the patch the CREAT TABLE statement would failed with +--echo # ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction +--reap + +--echo # Clean up. +DROP TABLE t1; +--disconnect con1 +--source include/wait_until_disconnected.inc + +--connection default +--disable_connect_log + diff --git a/sql/mdl.cc b/sql/mdl.cc index 06eebe137590..0d5a771b9d05 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -120,8 +120,8 @@ static void init_mdl_psi_keys() { */ PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END] = { - {0, "Waiting for global read lock", 0, PSI_DOCUMENT_ME}, {0, "Waiting for backup lock", 0, PSI_DOCUMENT_ME}, + {0, "Waiting for global read lock", 0, PSI_DOCUMENT_ME}, {0, "Waiting for tablespace metadata lock", 0, PSI_DOCUMENT_ME}, {0, "Waiting for schema metadata lock", 0, PSI_DOCUMENT_ME}, {0, "Waiting for table metadata lock", 0, PSI_DOCUMENT_ME}, diff --git a/sql/mdl.h b/sql/mdl.h index ae7aaf60efa6..eddec4428af1 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -376,10 +376,10 @@ struct MDL_key { update m_namespace_to_wait_state_name array in mdl.cc! Different types of objects exist in different namespaces - - GLOBAL is used for the global read lock. - BACKUP_LOCK is to block any operations that could cause inconsistent backup. Such operations are most DDL statements, and some administrative statements. + - GLOBAL is used for the global read lock. - TABLESPACE is for tablespaces. - SCHEMA is for schemas (aka databases). - TABLE is for tables and views. @@ -401,8 +401,8 @@ struct MDL_key { treatment - waiting is aborted if connection to client is lost. */ enum enum_mdl_namespace { - GLOBAL = 0, - BACKUP_LOCK, /* Oracle LOCK INSTANCE FOR BACKUP */ + BACKUP_LOCK = 0, /* Oracle LOCK INSTANCE FOR BACKUP */ + GLOBAL, TABLESPACE, SCHEMA, TABLE,