diff options
author | Venkatesh Duggirala <venkatesh.duggirala@oracle.com> | 2014-05-05 22:22:15 +0530 |
---|---|---|
committer | Venkatesh Duggirala <venkatesh.duggirala@oracle.com> | 2014-05-05 22:22:15 +0530 |
commit | 66d624b7d614c4477c4e63e35e39c54d06fb7d37 (patch) | |
tree | 3932fe811105a21ee4dadccd6e3b51475b89a789 /sql | |
parent | 16b81798aa1c7d17317e42da816556679628f51e (diff) | |
download | mariadb-git-66d624b7d614c4477c4e63e35e39c54d06fb7d37.tar.gz |
Bug#17638477 UNINSTALL AND INSTALL SEMI-SYNC PLUGIN CAUSES SLAVES TO BREAK
Problem: Uninstallation of semi sync plugin causes replication to
break.
Analysis: A semisync enabled replication is mutual agreement between
Master and Slave when the connection (I/O thread) is established.
Once I/O thread is started and if semisync is enabled on both
master and slave, master appends special magic header to events
using semisync plugin functions and sends it to slave. And slave
expects that each event will have that special magic header format
and reads those bytes using semisync plugin functions.
When semi sync replication is in use if users execute
uninstallation of the plugin on master, slave gets confused while
interpreting that event's content because it expects special
magic header at the beginning of the event. Slave SQL thread will
be stopped with "Missing magic number in the header" error.
Similar problem will happen if uninstallation of the plugin happens
on slave when semi sync replication is in in use. Master sends
the events with magic header and slave does not know about the
added magic header and thinks that it received a corrupted event.
Hence slave SQL thread stops with "Found corrupted event" error.
Fix: Uninstallation of semisync plugin will be blocked when semisync
replication is in use and will throw 'ER_UNKNOWN_ERROR' error.
To detect that semisync replication is in use, this patch uses
semisync status variable values.
> On Master, it checks for 'Rpl_semi_sync_master_status' to be OFF
before allowing the uninstallation of rpl_semi_sync_master plugin.
>> Rpl_semi_sync_master_status is OFF when
>>> there is no dump thread running
>>> there are no semisync slaves
> On Slave, it checks for 'Rpl_semi_sync_slave_status' to be OFF
before allowing the uninstallation of rpl_semi_sync_slave plugin.
>> Rpl_semi_sync_slave_status is OFF when
>>> there is no I/O thread running
>>> replication is asynchronous replication.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_plugin.cc | 43 | ||||
-rw-r--r-- | sql/sql_show.cc | 53 | ||||
-rw-r--r-- | sql/sql_show.h | 1 |
3 files changed, 97 insertions, 0 deletions
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); |