From 565f1bc4a1ccd9a7b853980d9aca5861d75ed104 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 30 Sep 2009 18:38:02 -0300 Subject: Bug#47525: MySQL crashed (Federated) On Mac OS X or Windows, sending a SIGHUP to the server or a asynchronous flush (triggered by flush_time), would cause the server to crash. The problem was that a hook used to detach client API handles wasn't prepared to handle cases where the thread does not have a associated session. The solution is to verify whether the thread has a associated session before trying to detach a handle. mysql-test/r/federated_debug.result: Add test case result for Bug#47525 mysql-test/t/federated_debug-master.opt: Debug point. mysql-test/t/federated_debug.test: Add test case for Bug#47525 sql/slave.cc: Check whether a the thread has a associated session. sql/sql_parse.cc: Add debug code to simulate a reload without thread session. --- mysql-test/r/federated_debug.result | 37 +++++++++++++++++++++++++++++++ mysql-test/t/federated_debug-master.opt | 1 + mysql-test/t/federated_debug.test | 39 +++++++++++++++++++++++++++++++++ sql/slave.cc | 2 +- sql/sql_parse.cc | 20 +++++++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/federated_debug.result create mode 100644 mysql-test/t/federated_debug-master.opt create mode 100644 mysql-test/t/federated_debug.test diff --git a/mysql-test/r/federated_debug.result b/mysql-test/r/federated_debug.result new file mode 100644 index 00000000000..a6659d065b2 --- /dev/null +++ b/mysql-test/r/federated_debug.result @@ -0,0 +1,37 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +# +# Bug#47525: MySQL crashed (Federated) +# +# Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +# Switch to master +CREATE TABLE t1(a INT) ENGINE=FEDERATED +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1'; +SELECT * FROM t1; +a +1 +# Start a asynchronous reload +# Wait for tables to be closed +# Ensure that the server didn't crash +SELECT * FROM t1; +a +1 +# Drop tables on master and slave +DROP TABLE t1; +DROP TABLE t1; +# Federated cleanup +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/t/federated_debug-master.opt b/mysql-test/t/federated_debug-master.opt new file mode 100644 index 00000000000..ad9ba4795af --- /dev/null +++ b/mysql-test/t/federated_debug-master.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_detached_thread_refresh diff --git a/mysql-test/t/federated_debug.test b/mysql-test/t/federated_debug.test new file mode 100644 index 00000000000..9de440f4d79 --- /dev/null +++ b/mysql-test/t/federated_debug.test @@ -0,0 +1,39 @@ +--source include/have_debug.inc +--source include/federated.inc + +--echo # +--echo # Bug#47525: MySQL crashed (Federated) +--echo # + +connection slave; +--echo # Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); + +connection master; +--echo # Switch to master +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE t1(a INT) ENGINE=FEDERATED + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1'; + +SELECT * FROM t1; + +--echo # Start a asynchronous reload +--exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= refresh 2>&1 + +--echo # Wait for tables to be closed +let $show_statement= SHOW STATUS LIKE 'Open_tables'; +let $field= Value; +let $condition= = '0'; +--source include/wait_show_condition.inc + +--echo # Ensure that the server didn't crash +SELECT * FROM t1; +--echo # Drop tables on master and slave +DROP TABLE t1; +connection slave; +DROP TABLE t1; + +connection default; +--echo # Federated cleanup +source include/federated_cleanup.inc; diff --git a/sql/slave.cc b/sql/slave.cc index 17855ed04e5..dd29a3f45c9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4756,7 +4756,7 @@ extern "C" void slave_io_thread_detach_vio() { #ifdef SIGNAL_WITH_VIO_CLOSE THD *thd= current_thd; - if (thd->slave_thread) + if (thd && thd->slave_thread) thd->clear_active_vio(); #endif } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 65b2a9d60b0..62cca71ee97 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2161,6 +2161,26 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_global_access(thd,RELOAD_ACL)) break; mysql_log.write(thd,command,NullS); +#ifndef DBUG_OFF + DBUG_EXECUTE_IF("simulate_detached_thread_refresh", + { + /* + Simulate a reload without a attached thread session. + Provides a environment similar to that of when the + server receives a SIGHUP signal and reloads caches + and flushes tables. + */ + bool res; + my_pthread_setspecific_ptr(THR_THD, NULL); + res= reload_acl_and_cache(NULL, options | REFRESH_FAST, + NULL, ¬_used); + my_pthread_setspecific_ptr(THR_THD, thd); + if (!res) + send_ok(thd); + break; + } + ); +#endif if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) send_ok(thd); break; -- cgit v1.2.1