summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavi Arnaut <Davi.Arnaut@Sun.COM>2009-09-30 18:38:02 -0300
committerDavi Arnaut <Davi.Arnaut@Sun.COM>2009-09-30 18:38:02 -0300
commitf474f75b38f4a9a897c2481aaedade87d91aa66c (patch)
treee494fb28c32b11ed12288677e44572035a31869e
parent0816b40e981209b64f415813111bfb58da3234a3 (diff)
downloadmariadb-git-f474f75b38f4a9a897c2481aaedade87d91aa66c.tar.gz
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.
-rw-r--r--mysql-test/r/federated_debug.result37
-rw-r--r--mysql-test/t/federated_debug-master.opt1
-rw-r--r--mysql-test/t/federated_debug.test39
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_parse.cc20
5 files changed, 98 insertions, 1 deletions
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, &not_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, &not_used))
send_ok(thd);
break;