diff --git a/mysql-test/include/stop_dump_threads.inc b/mysql-test/include/stop_dump_threads.inc new file mode 100644 index 00000000000..ae33c963d9a --- /dev/null +++ b/mysql-test/include/stop_dump_threads.inc @@ -0,0 +1,32 @@ +# ==== Purpose ==== +# +# Stop all dump threads on the server of the current connection. +# +# ==== Usage ==== +# +# --source include/stop_dump_threads.inc + +--let $include_filename= stop_dump_threads.inc +--source include/begin_include_file.inc + + +--let $_sdt_show_rpl_debug_info_old= $show_rpl_debug_info +--let $show_rpl_debug_info= 1 +--disable_query_log +--disable_result_log + +--let $_sdt_dump_thread_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Binlog dump'` + +while ($_sdt_dump_thread_id != '') +{ + eval KILL $_sdt_dump_thread_id; + --let $wait_condition= SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = $_sdt_dump_thread_id + --source include/wait_condition.inc + + --let $_sdt_dump_thread_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Binlog dump'` +} + +--let $show_rpl_debug_info= $_sdt_show_rpl_debug_info_old + +--let $include_filename= stop_dump_threads.inc +--source include/end_include_file.inc diff --git a/mysql-test/include/uninstall_semisync.inc b/mysql-test/include/uninstall_semisync.inc index 11668d1db97..0a4c55fa4f2 100644 --- a/mysql-test/include/uninstall_semisync.inc +++ b/mysql-test/include/uninstall_semisync.inc @@ -13,6 +13,11 @@ UNINSTALL PLUGIN rpl_semi_sync_slave; --connection master +# After BUG#17638477 fix, uninstallation of rpl_semi_sync_master +# is not allowed when there are semi sync slaves. Hence kill +# all dump threads before uninstalling it. +SET GLOBAL rpl_semi_sync_master_enabled = OFF; +--source include/stop_dump_threads.inc UNINSTALL PLUGIN rpl_semi_sync_master; --enable_warnings diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync.result b/mysql-test/suite/rpl/r/rpl_semi_sync.result index 0377716698c..8c6cb58324a 100644 --- a/mysql-test/suite/rpl/r/rpl_semi_sync.result +++ b/mysql-test/suite/rpl/r/rpl_semi_sync.result @@ -439,9 +439,8 @@ Rpl_semi_sync_slave_status OFF # # Clean up # +include/uninstall_semisync.inc include/stop_slave.inc -UNINSTALL PLUGIN rpl_semi_sync_slave; -UNINSTALL PLUGIN rpl_semi_sync_master; change master to master_user='root',master_password=''; include/start_slave.inc drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_uninstall_plugin.result b/mysql-test/suite/rpl/r/rpl_semi_sync_uninstall_plugin.result new file mode 100644 index 00000000000..d5cf690c978 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_uninstall_plugin.result @@ -0,0 +1,36 @@ +include/master-slave.inc +[connection master] +INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; +INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; +UNINSTALL PLUGIN rpl_semi_sync_slave; +UNINSTALL PLUGIN rpl_semi_sync_master; +CREATE TABLE t1(i int); +INSERT INTO t1 values (1); +DROP TABLE t1; +include/install_semisync.inc +call mtr.add_suppression("Plugin 'rpl_semi_sync_slave' cannot be uninstalled now"); +UNINSTALL PLUGIN rpl_semi_sync_slave; +ERROR HY000: Unknown error +call mtr.add_suppression("Plugin 'rpl_semi_sync_master' cannot be uninstalled now"); +UNINSTALL PLUGIN rpl_semi_sync_master; +ERROR HY000: Unknown error +CREATE TABLE t1(i int); +INSERT INTO t1 values (2); +DROP TABLE t1; +include/assert.inc [semi sync slave status should be ON.] +include/assert.inc [semi sync master status should be ON.] +include/assert.inc [semi sync master clients should be 1.] +SET GLOBAL rpl_semi_sync_master_enabled = OFF; +include/assert.inc [semi sync master clients should be 1.] +UNINSTALL PLUGIN rpl_semi_sync_master; +ERROR HY000: Unknown error +include/stop_slave.inc +SET GLOBAL rpl_semi_sync_slave_enabled = OFF; +include/start_slave.inc +UNINSTALL PLUGIN rpl_semi_sync_slave; +include/assert.inc [semi sync master clients should be 0.] +UNINSTALL PLUGIN rpl_semi_sync_master; +CREATE TABLE t1(i int); +INSERT INTO t1 values (3); +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync.test index 21967fb6f8c..b78bb772fc9 100644 --- a/mysql-test/suite/rpl/t/rpl_semi_sync.test +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test @@ -598,19 +598,10 @@ SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; --echo # --echo # Clean up --echo # +--source include/uninstall_semisync.inc connection slave; source include/stop_slave.inc; -UNINSTALL PLUGIN rpl_semi_sync_slave; - -connection master; -# The dump thread may still be running on the master, and so the following -# UNINSTALL could generate a warning about the plugin is busy. -disable_warnings; -UNINSTALL PLUGIN rpl_semi_sync_master; -enable_warnings; - -connection slave; change master to master_user='root',master_password=''; source include/start_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-master.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-master.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-slave.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-slave.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin-slave.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin.test b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin.test new file mode 100644 index 00000000000..094e044e0d2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_uninstall_plugin.test @@ -0,0 +1,143 @@ +############################################################################### +# Bug#17638477 UNINSTALL AND INSTALL SEMI-SYNC PLUGIN CAUSES SLAVES TO BREAK +# Problem: Uninstallation of Semi sync plugin should be blocked when it is +# in use. +# Test case: Uninstallation of semi sync should be allowed +# On Master: +# 1) When there is no dump thread +# 2) When there are no semi sync slaves (i.e., async replication). +# On Slave: +# 1) When there is no I/O thread +# 2) When there are no semi sync enabled I/O thread (i.e.,async replication). +############################################################################### + +--source include/have_semisync_plugin.inc +--source include/not_embedded.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +############################################################################### +# Case 1: Uninstallation of semi sync plugins should be allowed when it is +# not in use i.e., when asynchronous replication is active. +############################################################################### +# Step 1.1: Install semi sync master plugin on master +eval INSTALL PLUGIN rpl_semi_sync_master SONAME '$SEMISYNC_MASTER_PLUGIN'; + +# Step 1.2: Install semi sync slave plugin on slave +--connection slave +eval INSTALL PLUGIN rpl_semi_sync_slave SONAME '$SEMISYNC_SLAVE_PLUGIN'; + +# Step 1.3: Uninstallation of semisync plugin on master and slave should be +# allowed at this state as there is no semi sync replication enabled between +# master and slave. +UNINSTALL PLUGIN rpl_semi_sync_slave; +--connection master +UNINSTALL PLUGIN rpl_semi_sync_master; + +# Step 1.4: Check that replication is working fine at the end of the test case. +CREATE TABLE t1(i int); +INSERT INTO t1 values (1); +DROP TABLE t1; +--sync_slave_with_master + +############################################################################### +# Case 2: Uninstallation of semi sync plugins should be disallowed +# when it is in use i.e., when semi sync replication is active +############################################################################### +# Step 2.1: Install and enable semi sync replication between master and slave +--source include/install_semisync.inc + +# Step 2.2: Check that rpl_semi_sync_slave uninstallation on Slave is not +# possible at this state +--connection slave +call mtr.add_suppression("Plugin 'rpl_semi_sync_slave' cannot be uninstalled now"); +--error ER_UNKNOWN_ERROR +UNINSTALL PLUGIN rpl_semi_sync_slave; + +# Step 2.3: Check that rpl_semi_sync_master uninstallation on Master is not +# possible at this state +--connection master +call mtr.add_suppression("Plugin 'rpl_semi_sync_master' cannot be uninstalled now"); +--error ER_UNKNOWN_ERROR +UNINSTALL PLUGIN rpl_semi_sync_master; + +# Step 2.4: Check that replication is working fine at the end of the test case. +CREATE TABLE t1(i int); +INSERT INTO t1 values (2); +DROP TABLE t1; +--sync_slave_with_master + +# Step 2.5: Make sure rpl_semi_sync_master_status on Master and +# rpl_semi_sync_slave_staus on Slave are ON +--let $slave_status=[show status like "Rpl_semi_sync_slave_status", Value, 1] +--let assert_cond= "$slave_status" = "ON" +--let assert_text= semi sync slave status should be ON. +--source include/assert.inc + +--connection master +--let $master_status=[show status like "Rpl_semi_sync_master_status", Value, 1] +--let assert_cond= "$master_status" = "ON" +--let assert_text= semi sync master status should be ON. +--source include/assert.inc + +--let $master_clients=[show status like "Rpl_semi_sync_master_clients", Value, 1] +--let assert_cond= $master_clients = 1 +--let assert_text= semi sync master clients should be 1. +--source include/assert.inc + +############################################################################### +# Case 3: Uninstallation of semi sync plugin should be disallowed when there +# are semi sync slaves even though rpl_semi_sync_master_enabled= OFF;. +############################################################################### +# Step 3.1: Disable semi sync on master +--connection master +SET GLOBAL rpl_semi_sync_master_enabled = OFF; + +# Step 3.2: Check that still Rpl_semi_sync_master_clients is 1 +--let $master_clients=[show status like "Rpl_semi_sync_master_clients", Value, 1] +--let assert_cond= $master_clients = 1 +--let assert_text= semi sync master clients should be 1. +--source include/assert.inc + +# Step 3.3: Since Rpl_semi_sync_master_clients is 1, uninstallation of +# rpl_semi_sync_master should be disallowed. +--error ER_UNKNOWN_ERROR +UNINSTALL PLUGIN rpl_semi_sync_master; + +############################################################################### +# Case 4: Uninstallation of semi sync plugin should be allowed when it is not +# in use. Same as Case 1 but this case is to check the case after enabling and +# disabling semi sync replication. +############################################################################### + +# Step 4.1: Stop IO thread on slave. +--connection slave +--source include/stop_slave.inc + +# Step 4.2: Disable semi sync on slave. +SET GLOBAL rpl_semi_sync_slave_enabled = OFF; + +# Step 4.3: Start IO thread on slave. +--source include/start_slave.inc + +# Step 4.4: Uninstall semi sync plugin, it should be successful now. +UNINSTALL PLUGIN rpl_semi_sync_slave; + +# Step 4.5: On Master, check that semi sync slaves are now '0'. +--connection master +--let $master_clients=[show status like "Rpl_semi_sync_master_clients", Value, 1] +--let assert_cond= $master_clients = 0 +--let assert_text= semi sync master clients should be 0. +--source include/assert.inc + +# Step 4.6: So uninstalling semi sync plugin should be allowed +UNINSTALL PLUGIN rpl_semi_sync_master; + +# Step 4.7: Check that replication is working fine at the end of the test case +CREATE TABLE t1(i int); +INSERT INTO t1 values (3); +DROP TABLE t1; +--sync_slave_with_master + +# Cleanup +source include/rpl_end.inc; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d54326af7aa..9851cb2739a 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1930,6 +1930,49 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) goto err; } +#ifdef HAVE_REPLICATION + /* Block Uninstallation of semi_sync plugins (Master/Slave) + when they are busy + */ + char buff[20]; + /* + Master: If there are active semi sync slaves for this Master, + then that means it is busy and rpl_semi_sync_master plugin + cannot be uninstalled. To check whether the master + has any semi sync slaves or not, check Rpl_semi_sync_master_cliens + status variable value, if it is not 0, that means it is busy. + */ + if (!strcmp(name->str, "rpl_semi_sync_master") && + get_status_var(thd, + plugin->plugin->status_vars, + "Rpl_semi_sync_master_clients",buff) && + strcmp(buff,"0") ) + { + sql_print_error("Plugin 'rpl_semi_sync_master' cannot be uninstalled now. " + "Stop any active semisynchronous slaves of this master " + "first.\n"); + my_error(ER_UNKNOWN_ERROR, MYF(0), name->str); + goto err; + } + /* Slave: If there is semi sync enabled IO thread active on this Slave, + then that means plugin is busy and rpl_semi_sync_slave plugin + cannot be uninstalled. To check whether semi sync + IO thread is active or not, check Rpl_semi_sync_slave_status status + variable value, if it is ON, that means it is busy. + */ + if (!strcmp(name->str, "rpl_semi_sync_slave") && + get_status_var(thd, plugin->plugin->status_vars, + "Rpl_semi_sync_slave_status", buff) && + !strcmp(buff,"ON") ) + { + sql_print_error("Plugin 'rpl_semi_sync_slave' cannot be uninstalled now. " + "Stop any active semisynchronous I/O threads on this slave " + "first.\n"); + my_error(ER_UNKNOWN_ERROR, MYF(0), name->str); + goto err; + } +#endif + plugin->state= PLUGIN_IS_DELETED; if (plugin->ref_count) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index dcae4c63b02..ac63b2aaff9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2117,6 +2117,59 @@ void free_status_vars() delete_dynamic(&all_status_vars); } +/** + @brief Get the value of given status variable + + @param[in] thd thread handler + @param[in] list list of SHOW_VAR objects in which function should + search + @param[in] name name of the status variable + @param[in/out] value buffer in which value of the status variable + needs to be filled in + + @return status + @retval FALSE if variable is not found in the list + @retval TRUE if variable is found in the list + NOTE: Currently this function is implemented just to support 'bool' status + variables and 'long' status variables *only*. It can be extended very easily + for further show_types in future if required. + TODO: Currently show_status_arary switch case is tightly coupled with + pos, end, buff, value variables and also it stores the values in a 'table'. + Decouple the switch case to fill the buffer value so that it can be used + in show_status_array() and get_status_var() to avoid duplicate code. + */ + +bool get_status_var(THD* thd, SHOW_VAR *list, const char * name, char * const value) +{ + for (; list->name; list++) + { + int res= strcmp(list->name, name); + if (res == 0) + { + /* + if var->type is SHOW_FUNC, call the function. + Repeat as necessary, if new var is again SHOW_FUNC + */ + SHOW_VAR tmp; + for (; list->type == SHOW_FUNC; list= &tmp) + ((mysql_show_var_func)(list->value))(thd, &tmp, value); + switch (list->type) { + case SHOW_BOOL: + strmov(value, *(bool*) list->value ? "ON" : "OFF"); + break; + case SHOW_LONG: + int10_to_str(*(long*) list->value, value, 10); + break; + default: + /* not supported type */ + DBUG_ASSERT(0); + } + return TRUE; + } + } + return FALSE; +} + /* Removes an array of SHOW_VAR entries from the output of SHOW STATUS diff --git a/sql/sql_show.h b/sql/sql_show.h index 406c75d8cbe..b6d520441c7 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -113,6 +113,7 @@ int add_status_vars(SHOW_VAR *list); void remove_status_vars(SHOW_VAR *list); void init_status_vars(); void free_status_vars(); +bool get_status_var(THD* thd, SHOW_VAR *list, const char *name, char * const buff); void reset_status_vars(); bool show_create_trigger(THD *thd, const sp_name *trg_name); void view_store_options(THD *thd, TABLE_LIST *table, String *buff);