From af31e2c55d569de343b2b855131e73c0138e7c2d Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 14 Feb 2021 17:42:19 +0200 Subject: [PATCH] MDEV-23843 Assertions in Diagnostics_area upon table operations under FTWRL 2 different problems: - MYSQL_BIN_LOG::write() did not check if mdl_context.acquire_lock() failed - Sql_cmd_optimize_table::execute() and Sql_cmd_repair_table::execute() called write_bin_log(), which could fail if sql_admin() had already called my_eof() Fixed by adding check for aquire_lock() return status and protect write_bin_log() in the above two functions with set_overwrite_status(). --- mysql-test/main/flush_and_binlog.result | 22 +++++++++++++++++++ mysql-test/main/flush_and_binlog.test | 29 +++++++++++++++++++++++++ sql/log.cc | 5 +++-- sql/sql_admin.cc | 4 ++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 mysql-test/main/flush_and_binlog.result create mode 100644 mysql-test/main/flush_and_binlog.test diff --git a/mysql-test/main/flush_and_binlog.result b/mysql-test/main/flush_and_binlog.result new file mode 100644 index 00000000000..b9560964046 --- /dev/null +++ b/mysql-test/main/flush_and_binlog.result @@ -0,0 +1,22 @@ +# +# MDEV-23843 Assertions in Diagnostics_area upon table operations under +# FTWRL +# +CREATE TABLE t1 (a INT); +FLUSH TABLES WITH READ LOCK; +connect con1,localhost,root,,; +SET lock_wait_timeout= 1; +OPTIMIZE TABLE t1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +disconnect con1; +connection default; +UNLOCK TABLES; +DROP TABLE t1; +FLUSH TABLES WITH READ LOCK; +connect con1,localhost,root,,test; +SET lock_wait_timeout= 1; +FLUSH TABLES; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +connection default; +disconnect con1; +unlock tables; diff --git a/mysql-test/main/flush_and_binlog.test b/mysql-test/main/flush_and_binlog.test new file mode 100644 index 00000000000..373b900b451 --- /dev/null +++ b/mysql-test/main/flush_and_binlog.test @@ -0,0 +1,29 @@ +--source include/have_log_bin.inc + +--echo # +--echo # MDEV-23843 Assertions in Diagnostics_area upon table operations under +--echo # FTWRL +--echo # + +CREATE TABLE t1 (a INT); +FLUSH TABLES WITH READ LOCK; +--connect (con1,localhost,root,,) +SET lock_wait_timeout= 1; +--error ER_LOCK_WAIT_TIMEOUT +OPTIMIZE TABLE t1; +# Cleanup +--disconnect con1 +--connection default +UNLOCK TABLES; +DROP TABLE t1; +# +# Second test case from MDEV_23843 +# +FLUSH TABLES WITH READ LOCK; +--connect (con1,localhost,root,,test) +SET lock_wait_timeout= 1; +--error ER_LOCK_WAIT_TIMEOUT +FLUSH TABLES; +--connection default +--disconnect con1 +unlock tables; diff --git a/sql/log.cc b/sql/log.cc index 480e3b696cc..2a1142d8391 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -6390,8 +6390,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) DBUG_ASSERT(!thd->backup_commit_lock); mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); - thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout); + if (thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout)) + DBUG_RETURN(1); thd->backup_commit_lock= &mdl_request; if ((res= thd->wait_for_prior_commit())) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 0a6e76d117f..c9185045315 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1455,7 +1455,9 @@ bool Sql_cmd_optimize_table::execute(THD *thd) /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */ + thd->get_stmt_da()->set_overwrite_status(true); res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + thd->get_stmt_da()->set_overwrite_status(false); } m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; @@ -1487,7 +1489,9 @@ bool Sql_cmd_repair_table::execute(THD *thd) /* Presumably, REPAIR and binlog writing doesn't require synchronization */ + thd->get_stmt_da()->set_overwrite_status(true); res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + thd->get_stmt_da()->set_overwrite_status(false); } m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table;