diff options
author | Brandon Nesterenko <brandon.nesterenko@mariadb.com> | 2022-04-04 07:35:48 -0600 |
---|---|---|
committer | Brandon Nesterenko <brandon.nesterenko@mariadb.com> | 2022-04-18 16:06:51 -0600 |
commit | d924a30eb9c92731548bae8476255fde6642cd86 (patch) | |
tree | 6ba425c65b1d2013e9a57bdc29774cb5d37aa1f6 | |
parent | e4e25d2bacc067417c35750f5f6c44cad10c81de (diff) | |
download | mariadb-git-d924a30eb9c92731548bae8476255fde6642cd86.tar.gz |
MDEV-25768: ALTER gtid_slave_pos table storage engine should not be allowed when slave is running.bb-10.2-MDEV-25768
Problem:
========
The mysql.gtid_slave_pos table can have its engine modified while
the SQL thread is alive.
Solution:
========
Use MDL locks to ensure that the table can only have its
engine modified when the slave SQL thread is not running.
Reviewed By:
============
TODO
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_alter_gtid_slave_pos_engine.result | 125 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_mdev10863.result | 9 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_alter_gtid_slave_pos_engine.test | 221 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_mdev10863.test | 13 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/slave.cc | 31 | ||||
-rw-r--r-- | sql/sql_rename.cc | 28 | ||||
-rw-r--r-- | sql/sql_table.cc | 33 |
8 files changed, 452 insertions, 10 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_alter_gtid_slave_pos_engine.result b/mysql-test/suite/rpl/r/rpl_alter_gtid_slave_pos_engine.result new file mode 100644 index 00000000000..f258cb3fdfc --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_alter_gtid_slave_pos_engine.result @@ -0,0 +1,125 @@ +include/master-slave.inc +[connection master] +connection slave; +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +call mtr.add_suppression("Slave: This operation cannot be performed as you have a running slave with parallel threads.*"); +# +# Trying to alter gtid_slave_pos table while slave has parallel threads +# should result in an error +# +connection slave; +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +include/start_slave.inc +# Slave_SQL_Running: Yes +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +ERROR HY000: This operation cannot be performed as you have a running slave with parallel threads. Either stop the slave or disable parallelism first. +# +# Altering gtid_slave_pos engine while slave SQL thread is stopped should +# succeed +# +include/stop_slave.inc +# Slave_SQL_Running: No +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +include/start_slave.inc +# Reset gtid_slave_pos engine +include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +include/start_slave.inc +# +# Altering gtid_slave_pos engine on serial slave should succeed +# +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +include/start_slave.inc +# Slave_SQL_Running: Yes +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +include/start_slave.inc +Warnings: +Note 1254 Slave is already running +# Reset gtid_slave_pos engine +include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +include/start_slave.inc +# +# Replicating gtid_slave_pos engine change from master to serial slave +# should succeed +# +connection slave; +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +include/start_slave.inc +connection master; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +# Reset gtid_slave_pos engine +connection master; +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +# +# Replicating gtid_slave_pos engine change from master to parallel slave +# should fail +# +connection slave; +include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +SET GLOBAL slave_parallel_threads=1; +include/start_slave.inc +connection master; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +include/save_master_gtid.inc +connection slave; +include/wait_for_slave_sql_error.inc [errno=4054] +# Skip the problem event from the master. +include/stop_slave.inc +SET sql_slave_skip_counter=1; +include/start_slave.inc +include/sync_with_master_gtid.inc +# +# Renaming gtid_slave_pos table while slave has parallel threads should +# result in an error +# +connection slave; +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=1; +include/start_slave.inc +# Slave_SQL_Running: Yes +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +ERROR HY000: This operation cannot be performed as you have a running slave with parallel threads. Either stop the slave or disable parallelism first. +# +# Renaming gtid_slave_pos table on serial slave should succeed +# +connection slave; +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +include/start_slave.inc +# Slave_SQL_Running: Yes +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +# Revert table name +RENAME TABLE mysql.gtid_slave_pos_v2 TO mysql.gtid_slave_pos; +# +# Renaming gtid_slave_pos table should succeed on stopped slave +# +connection slave; +# Slave_SQL_Running: Yes +include/stop_slave.inc +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +include/start_slave.inc +# Revert table name +include/stop_slave.inc +RENAME TABLE mysql.gtid_slave_pos_v2 TO mysql.gtid_slave_pos; +include/start_slave.inc +# +# Cleanup +# +connection slave; +include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_mdev10863.result b/mysql-test/suite/rpl/r/rpl_mdev10863.result index 158d4a921b7..d7ed88fbcf5 100644 --- a/mysql-test/suite/rpl/r/rpl_mdev10863.result +++ b/mysql-test/suite/rpl/r/rpl_mdev10863.result @@ -2,13 +2,18 @@ include/rpl_init.inc [topology=1->2] connection server_2; SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +CHANGE MASTER TO master_use_gtid=slave_pos; +include/start_slave.inc +connection server_1; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +connection server_2; +include/stop_slave.inc SET GLOBAL slave_parallel_threads=10; SET @old_max_relay= @@GLOBAL.max_relay_log_size; SET GLOBAL max_relay_log_size = 4096; -CHANGE MASTER TO master_use_gtid=slave_pos; include/start_slave.inc connection server_1; -ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; CREATE TABLE t1 (a int PRIMARY KEY, b VARCHAR(100)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, "a"); connection server_2; diff --git a/mysql-test/suite/rpl/t/rpl_alter_gtid_slave_pos_engine.test b/mysql-test/suite/rpl/t/rpl_alter_gtid_slave_pos_engine.test new file mode 100644 index 00000000000..eca5d9e91a9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_gtid_slave_pos_engine.test @@ -0,0 +1,221 @@ +# +# Purpose: +# This test ensures that the engine/table_name of the mysql.gtid_slave_pos +# table can only be changed if the slave is in serial mode (no parallel +# threads). +# +# References: +# MDEV-25768: ALTER gtid_slave_pos table storage engine should not be allowed +# when slave is running + +--source include/have_innodb.inc +--source include/master-slave.inc + +# Changing gtid_slave_pos table is format independent so just use one for +# reduced test time +--source include/have_binlog_format_row.inc + +--connection slave +--let old_slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +call mtr.add_suppression("Slave: This operation cannot be performed as you have a running slave with parallel threads.*"); + + +--echo # +--echo # Trying to alter gtid_slave_pos table while slave has parallel threads +--echo # should result in an error +--echo # +--connection slave +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Slave_SQL_Running: $slave_sql_running +--error 4054 +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if ($old_slave_pos_engine != $slave_pos_engine) +{ + --die gtid_slave_pos engine should not have changed if slave has active parallel threads +} + + +--echo # +--echo # Altering gtid_slave_pos engine while slave SQL thread is stopped should +--echo # succeed +--echo # +--source include/stop_slave.inc +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) +--echo # Slave_SQL_Running: $slave_sql_running +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +--source include/start_slave.inc +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if ($old_slave_pos_engine == $slave_pos_engine) +{ + --die gtid_slave_pos engine should have changed with a stopped slave +} + +--echo # Reset gtid_slave_pos engine +--source include/stop_slave.inc +--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine +--source include/start_slave.inc + + +--echo # +--echo # Altering gtid_slave_pos engine on serial slave should succeed +--echo # +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +--source include/start_slave.inc +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) +--echo # Slave_SQL_Running: $slave_sql_running +ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb; +--source include/start_slave.inc +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if ($old_slave_pos_engine == $slave_pos_engine) +{ + --die gtid_slave_pos engine should have changed on a serial slave +} + +--echo # Reset gtid_slave_pos engine +--source include/stop_slave.inc +--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine +--source include/start_slave.inc + + +--echo # +--echo # Replicating gtid_slave_pos engine change from master to serial slave +--echo # should succeed +--echo # +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +--source include/start_slave.inc + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if ($old_slave_pos_engine == $slave_pos_engine) +{ + --die gtid_slave_pos engine change should have replicated from master on serial slave +} + +--echo # Reset gtid_slave_pos engine +--connection master +--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc + + +--echo # +--echo # Replicating gtid_slave_pos engine change from master to parallel slave +--echo # should fail +--echo # +--connection slave +--source include/stop_slave.inc +--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine +SET GLOBAL slave_parallel_threads=1; +--source include/start_slave.inc + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +--source include/save_master_gtid.inc + +--connection slave +--let $slave_sql_errno=4054 +--source include/wait_for_slave_sql_error.inc + +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if ($old_slave_pos_engine != $slave_pos_engine) +{ + --die gtid_slave_pos engine change from master should fail on parallel slave +} + +--echo # Skip the problem event from the master. +--source include/stop_slave.inc +#SET GLOBAL gtid_slave_pos= "0-1-3"; +SET sql_slave_skip_counter=1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + + +--echo # +--echo # Renaming gtid_slave_pos table while slave has parallel threads should +--echo # result in an error +--echo # +--connection slave +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=1; +--source include/start_slave.inc + +--echo # Slave_SQL_Running: $slave_sql_running +--error 4054 +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if (`SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' AND table_name='gtid_slave_pos_v2'`) +{ + --die gtid_slave_pos rename should fail on slave with active parallel threads +} + + +--echo # +--echo # Renaming gtid_slave_pos table on serial slave should succeed +--echo # +--connection slave +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +--source include/start_slave.inc + +--echo # Slave_SQL_Running: $slave_sql_running +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if (`SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' AND table_name='gtid_slave_pos'`) +{ + --die gtid_slave_pos rename should succeed for serial slave +} +--echo # Revert table name +RENAME TABLE mysql.gtid_slave_pos_v2 TO mysql.gtid_slave_pos; + + +--echo # +--echo # Renaming gtid_slave_pos table should succeed on stopped slave +--echo # +--connection slave +--let slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) + +--echo # Slave_SQL_Running: $slave_sql_running +--source include/stop_slave.inc +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_v2; +--source include/start_slave.inc +--let slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1) +if (`SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' AND table_name='gtid_slave_pos'`) +{ + --die gtid_slave_pos rename should succeed for stopped slave +} +--echo # Revert table name +--source include/stop_slave.inc +RENAME TABLE mysql.gtid_slave_pos_v2 TO mysql.gtid_slave_pos; +--source include/start_slave.inc + +--echo # +--echo # Cleanup +--echo # +--connection slave +--source include/stop_slave.inc +--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev10863.test b/mysql-test/suite/rpl/t/rpl_mdev10863.test index 796e770672d..a4ce80d1bf5 100644 --- a/mysql-test/suite/rpl/t/rpl_mdev10863.test +++ b/mysql-test/suite/rpl/t/rpl_mdev10863.test @@ -7,14 +7,23 @@ --connection server_2 SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; --source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc SET GLOBAL slave_parallel_threads=10; SET @old_max_relay= @@GLOBAL.max_relay_log_size; SET GLOBAL max_relay_log_size = 4096; -CHANGE MASTER TO master_use_gtid=slave_pos; --source include/start_slave.inc --connection server_1 -ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; CREATE TABLE t1 (a int PRIMARY KEY, b VARCHAR(100)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, "a"); --save_master_pos diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 814716b0a97..9919c7f081d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7664,6 +7664,8 @@ ER_SLAVE_SAME_ID eng "A slave with the same server_uuid/server_id as this slave has connected to the master" ER_FLASHBACK_NOT_SUPPORTED eng "Flashback does not support %s %s" +ER_SLAVE_IS_PARALLEL + eng "This operation cannot be performed as you have a running slave with parallel threads. Either stop the slave or disable parallelism first." diff --git a/sql/slave.cc b/sql/slave.cc index 2ff1a0490e9..7f851b2cecd 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4801,6 +4801,10 @@ pthread_handler_t handle_slave_sql(void *arg) const char *errmsg; rpl_group_info *serial_rgi; rpl_sql_thread_info sql_info(mi->rpl_filter); + MDL_request mdl_req_gtid_slave_state; + mdl_req_gtid_slave_state.init(MDL_key::TABLE, "mysql", + rpl_gtid_slave_state_table_name.str, + MDL_SHARED_WRITE, MDL_EXPLICIT); // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); @@ -4840,13 +4844,25 @@ pthread_handler_t handle_slave_sql(void *arg) pthread_detach_this_thread(); - if (opt_slave_parallel_threads > 0 && - rpl_parallel_activate_pool(&global_rpl_thread_pool)) + if (opt_slave_parallel_threads > 0) { - mysql_cond_broadcast(&rli->start_cond); - rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL, - "Failed during parallel slave pool activation"); - goto err_during_init; + if (rpl_parallel_activate_pool(&global_rpl_thread_pool)) + { + mysql_cond_broadcast(&rli->start_cond); + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL, + "Failed during parallel slave pool activation"); + goto err_during_init; + } + /* + Prevent the gtid_slave_pos from having its engine altered while the SQL + thread is running. + */ + if (thd->mdl_context.acquire_lock(&mdl_req_gtid_slave_state, + thd->variables.lock_wait_timeout)) + { + my_error(ER_CANT_LOCK, MYF(0)); + goto err; + } } if (init_slave_thread(thd, mi, SLAVE_THD_SQL)) @@ -5300,6 +5316,9 @@ err_during_init: delete serial_rgi; mysql_mutex_unlock(&LOCK_thread_count); + if (mdl_req_gtid_slave_state.ticket) + thd->mdl_context.release_lock(mdl_req_gtid_slave_state.ticket); + delete thd; thread_safe_decrement32(&service_thread_count); signal_thd_deleted(); diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index af4a6ca3ce1..53d539e8be3 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -30,6 +30,8 @@ #include "sql_base.h" // tdc_remove_table, lock_table_names, #include "sql_handler.h" // mysql_ha_rm_tables #include "sql_statistics.h" +#include "rpl_rli.h" +#include "rpl_gtid.h" static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error); @@ -51,6 +53,10 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) TABLE_LIST *ren_table= 0; int to_table; char *rename_log_table[2]= {NULL, NULL}; +#ifdef HAVE_REPLICATION + MDL_request mdl_req_gtid_slave_state; + mdl_req_gtid_slave_state.ticket= NULL; +#endif DBUG_ENTER("mysql_rename_tables"); /* @@ -140,6 +146,28 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) } } +#ifdef HAVE_REPLICATION + /* + The gtid slave state table (gtid_slave_pos) cannot be renamed if the slave + has parallel threads. The table's MDL lock is held when the slave is + running with parallel threads. + */ + if (!(strncmp(table_list->db, C_STRING_WITH_LEN("mysql")) || + strncmp(table_list->table_name, rpl_gtid_slave_state_table_name.str, + rpl_gtid_slave_state_table_name.length))) + { + mdl_req_gtid_slave_state.init(MDL_key::TABLE, "mysql", + rpl_gtid_slave_state_table_name.str, + MDL_SHARED_NO_WRITE, MDL_TRANSACTION); + if (!thd->mdl_context.try_acquire_lock(&mdl_req_gtid_slave_state) && + !mdl_req_gtid_slave_state.ticket) + { + my_error(ER_SLAVE_IS_PARALLEL, MYF(0)); + goto err; + } + } +#endif + if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout, 0)) goto err; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a2dc5c97aeb..70e94baa1c8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8974,6 +8974,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ int table_kind= check_if_log_table(table_list, FALSE, NullS); +#ifdef HAVE_REPLICATION + MDL_request mdl_req_gtid_slave_state; + mdl_req_gtid_slave_state.ticket= NULL; +#endif + if (table_kind) { /* Disable alter of enabled log tables */ @@ -9213,6 +9218,29 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, DBUG_RETURN(true); } +#ifdef HAVE_REPLICATION + /* + The engine of the gtid slave state table (gtid_slave_pos) cannot be changed + if the slave has parallel threads. The table's MDL lock is held when the + slave is running with parallel threads. + */ + if ((old_db_type != new_db_type || alter_ctx.is_table_renamed()) && + !(strncmp(alter_ctx.db, C_STRING_WITH_LEN("mysql")) || + strncmp(alter_ctx.table_name, rpl_gtid_slave_state_table_name.str, + rpl_gtid_slave_state_table_name.length))) + { + mdl_req_gtid_slave_state.init(MDL_key::TABLE, "mysql", + rpl_gtid_slave_state_table_name.str, + MDL_SHARED_NO_WRITE, MDL_EXPLICIT); + if (!thd->mdl_context.try_acquire_lock(&mdl_req_gtid_slave_state) && + !mdl_req_gtid_slave_state.ticket) + { + my_error(ER_SLAVE_IS_PARALLEL, MYF(0)); + DBUG_RETURN(true); + } + } +#endif + if (table->s->tmp_table == NO_TMP_TABLE) mysql_audit_alter_table(thd, table_list); @@ -9987,6 +10015,11 @@ end_inplace: mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); } +#ifdef HAVE_REPLICATION + if (mdl_req_gtid_slave_state.ticket) + thd->mdl_context.release_lock(mdl_req_gtid_slave_state.ticket); +#endif + end_temporary: my_snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name), ER_THD(thd, ER_INSERT_INFO), |