Commit 14aa44bb authored by Praveenkumar Hulakund's avatar Praveenkumar Hulakund

Bug#18903155: BACKPORT BUG-18008907 TO 5.5+ VERSIONS.

Backporting patch committed for bug 18008907 to 5.5
and 5.6.
parent 854da5e9
...@@ -143,3 +143,73 @@ SELECT @@SESSION.example_double_thdvar; ...@@ -143,3 +143,73 @@ SELECT @@SESSION.example_double_thdvar;
@@SESSION.example_double_thdvar @@SESSION.example_double_thdvar
1000.500000 1000.500000
UNINSTALL PLUGIN example; UNINSTALL PLUGIN example;
#
# BUG#18008907 - DEADLOCK BETWEEN MYSQL_CHANGE_USER(), SHOW VARIABLES AND INSTALL PLUGIN
#
CREATE PROCEDURE p_install()
BEGIN
INSTALL PLUGIN no_such_plugin SONAME 'no_such_object';
END
|
CREATE PROCEDURE p_show_vars()
BEGIN
SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES;
END|
connect con1, localhost, root,,;
# Case 18008907_1: Deadlock situation cause by
# con1: has LOCK_system_variables_hash and waits on LOCK_plugin AND
# default: has LOCK_plugin and waits on LOCK_system_variables_hash.
#
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL install_plugin WAIT_FOR cont_show_vars';
call p_show_vars();;
connection default;
SET DEBUG_SYNC='now WAIT_FOR install_plugin';
SET DEBUG_SYNC='acquired_LOCK_plugin SIGNAL cont_show_vars';
call p_install();;
connection con1;
COUNT(*)
#
SET DEBUG_SYNC='RESET';
connection default;
ERROR HY000: Can't open shared library
SET DEBUG_SYNC='RESET';
# Case 18008907_2: Deadlock situation caused by
# default: has LOCK_system_variables_hash and waits on LOCK_global_system_variables,
# con1: has LOCK_plugin and waits on LOCK_system_variables_hash AND
# con2: has LOCK_global_system_variables and waits on LOCK_plugin.
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL install_plugin WAIT_FOR nothing TIMEOUT 10';
call p_show_vars();;
connection con1;
SET DEBUG_SYNC='now WAIT_FOR install_plugin';
SET DEBUG_SYNC='acquired_LOCK_plugin SIGNAL create_connection WAIT_FOR nothing TIMEOUT 10';
call p_install();;
connect con2, localhost, root,,;
SET DEBUG_SYNC='now WAIT_FOR create_connection';
connection con1;
ERROR HY000: Can't open shared library
connection default;
COUNT(*)
#
Warnings:
# 1639 debug sync point wait timed out
disconnect con2;
# Case 18008907_3: Testing Concurrent "Show Variables" and "Plugin Uninstall" operations.
INSTALL PLUGIN example SONAME 'ha_example.so';
connection con1;
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL uninstall_plugin WAIT_FOR go';
call p_show_vars();;
connect con2, localhost, root,,;
SET DEBUG_SYNC='now WAIT_FOR uninstall_plugin';
UNINSTALL PLUGIN example;;
connection default;
SET DEBUG_SYNC='now SIGNAL go';
connection con1;
COUNT(*)
#
connection con2;
connection default;
DROP PROCEDURE p_show_vars;
DROP PROCEDURE p_install;
SET DEBUG_SYNC='RESET';
disconnect con1;
disconnect con2;
#
--source include/not_windows_embedded.inc --source include/not_windows_embedded.inc
--source include/have_example_plugin.inc --source include/have_example_plugin.inc
--source include/have_debug_sync.inc
CREATE TABLE t1(a int) ENGINE=EXAMPLE; CREATE TABLE t1(a int) ENGINE=EXAMPLE;
DROP TABLE t1; DROP TABLE t1;
...@@ -137,3 +139,118 @@ SET SESSION example_double_thdvar = 1000.51; ...@@ -137,3 +139,118 @@ SET SESSION example_double_thdvar = 1000.51;
SELECT @@SESSION.example_double_thdvar; SELECT @@SESSION.example_double_thdvar;
UNINSTALL PLUGIN example; UNINSTALL PLUGIN example;
--echo #
--echo # BUG#18008907 - DEADLOCK BETWEEN MYSQL_CHANGE_USER(), SHOW VARIABLES AND INSTALL PLUGIN
--echo #
--enable_connect_log
delimiter |;
CREATE PROCEDURE p_install()
BEGIN
INSTALL PLUGIN no_such_plugin SONAME 'no_such_object';
END
|
CREATE PROCEDURE p_show_vars()
BEGIN
SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES;
END|
delimiter ;|
connect(con1, localhost, root,,);
--echo # Case 18008907_1: Deadlock situation cause by
--echo # con1: has LOCK_system_variables_hash and waits on LOCK_plugin AND
--echo # default: has LOCK_plugin and waits on LOCK_system_variables_hash.
--echo #
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL install_plugin WAIT_FOR cont_show_vars';
--send call p_show_vars();
connection default;
SET DEBUG_SYNC='now WAIT_FOR install_plugin';
SET DEBUG_SYNC='acquired_LOCK_plugin SIGNAL cont_show_vars';
--send call p_install();
connection con1;
# Without fix, reap will hang.
--replace_column 1 #
--reap;
SET DEBUG_SYNC='RESET';
connection default;
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY
--reap;
SET DEBUG_SYNC='RESET';
--echo # Case 18008907_2: Deadlock situation caused by
--echo # default: has LOCK_system_variables_hash and waits on LOCK_global_system_variables,
--echo # con1: has LOCK_plugin and waits on LOCK_system_variables_hash AND
--echo # con2: has LOCK_global_system_variables and waits on LOCK_plugin.
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL install_plugin WAIT_FOR nothing TIMEOUT 10';
--send call p_show_vars();
connection con1;
SET DEBUG_SYNC='now WAIT_FOR install_plugin';
SET DEBUG_SYNC='acquired_LOCK_plugin SIGNAL create_connection WAIT_FOR nothing TIMEOUT 10';
--send call p_install();
connect(con2, localhost, root,,);
SET DEBUG_SYNC='now WAIT_FOR create_connection';
# Without fix, deadlock situation will occur on timeout of debug_syncs in
# default and con1. Because of this, change_user operation hangs.
change_user;
connection con1;
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY
--reap;
connection default;
--replace_column 1 #
--reap;
disconnect con2;
--echo # Case 18008907_3: Testing Concurrent "Show Variables" and "Plugin Uninstall" operations.
#Installing plugin
--replace_regex /\.dll/.so/
eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN';
connection con1;
#Acquiring LOCK_system_variables_hash and LOCK_plugin_delete
SET DEBUG_SYNC='acquired_LOCK_system_variables_hash SIGNAL uninstall_plugin WAIT_FOR go';
--send call p_show_vars();
connect(con2, localhost, root,,);
SET DEBUG_SYNC='now WAIT_FOR uninstall_plugin';
--send UNINSTALL PLUGIN example;
connection default;
#Plugin Uninstall operation will wait until show variables operations releases LOCK_plugin_delete.
let $wait_condition= SELECT count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE INFO LIKE 'UNINSTALL PLUGIN example' and
STATE LIKE 'Waiting on cond';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL go';
connection con1;
--replace_column 1 #
--reap
connection con2;
--reap
connection default;
DROP PROCEDURE p_show_vars;
DROP PROCEDURE p_install;
SET DEBUG_SYNC='RESET';
disconnect con1;
disconnect con2;
--disable_connect_log
File mode changed from 100644 to 100755
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "sql_audit.h" #include "sql_audit.h"
#include <mysql/plugin_auth.h> #include <mysql/plugin_auth.h>
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#include "debug_sync.h"
#define REPORT_TO_LOG 1 #define REPORT_TO_LOG 1
#define REPORT_TO_USER 2 #define REPORT_TO_USER 2
...@@ -131,6 +132,12 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= ...@@ -131,6 +132,12 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
#include "sql_plugin_services.h" #include "sql_plugin_services.h"
/*
A mutex LOCK_plugin_delete must be acquired before calling plugin_del
function.
*/
mysql_mutex_t LOCK_plugin_delete;
/* /*
A mutex LOCK_plugin must be acquired before accessing the A mutex LOCK_plugin must be acquired before accessing the
following variables/structures. following variables/structures.
...@@ -949,6 +956,7 @@ static void plugin_del(struct st_plugin_int *plugin) ...@@ -949,6 +956,7 @@ static void plugin_del(struct st_plugin_int *plugin)
{ {
DBUG_ENTER("plugin_del(plugin)"); DBUG_ENTER("plugin_del(plugin)");
mysql_mutex_assert_owner(&LOCK_plugin); mysql_mutex_assert_owner(&LOCK_plugin);
mysql_mutex_assert_owner(&LOCK_plugin_delete);
/* Free allocated strings before deleting the plugin. */ /* Free allocated strings before deleting the plugin. */
mysql_rwlock_wrlock(&LOCK_system_variables_hash); mysql_rwlock_wrlock(&LOCK_system_variables_hash);
mysql_del_sys_var_chain(plugin->system_vars); mysql_del_sys_var_chain(plugin->system_vars);
...@@ -996,11 +1004,14 @@ static void reap_plugins(void) ...@@ -996,11 +1004,14 @@ static void reap_plugins(void)
while ((plugin= *(--list))) while ((plugin= *(--list)))
plugin_deinitialize(plugin, true); plugin_deinitialize(plugin, true);
mysql_mutex_lock(&LOCK_plugin_delete);
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
while ((plugin= *(--reap))) while ((plugin= *(--reap)))
plugin_del(plugin); plugin_del(plugin);
mysql_mutex_unlock(&LOCK_plugin_delete);
my_afree(reap); my_afree(reap);
} }
...@@ -1205,10 +1216,12 @@ static inline void convert_underscore_to_dash(char *str, int len) ...@@ -1205,10 +1216,12 @@ static inline void convert_underscore_to_dash(char *str, int len)
#ifdef HAVE_PSI_INTERFACE #ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_LOCK_plugin; static PSI_mutex_key key_LOCK_plugin;
static PSI_mutex_key key_LOCK_plugin_delete;
static PSI_mutex_info all_plugin_mutexes[]= static PSI_mutex_info all_plugin_mutexes[]=
{ {
{ &key_LOCK_plugin, "LOCK_plugin", PSI_FLAG_GLOBAL} { &key_LOCK_plugin, "LOCK_plugin", PSI_FLAG_GLOBAL},
{ &key_LOCK_plugin_delete, "LOCK_plugin_delete", PSI_FLAG_GLOBAL}
}; };
static void init_plugin_psi_keys(void) static void init_plugin_psi_keys(void)
...@@ -1259,6 +1272,7 @@ int plugin_init(int *argc, char **argv, int flags) ...@@ -1259,6 +1272,7 @@ int plugin_init(int *argc, char **argv, int flags)
mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_plugin_delete, &LOCK_plugin_delete, MY_MUTEX_INIT_FAST);
if (my_init_dynamic_array(&plugin_dl_array, if (my_init_dynamic_array(&plugin_dl_array,
sizeof(struct st_plugin_dl *),16,16) || sizeof(struct st_plugin_dl *),16,16) ||
...@@ -1401,8 +1415,10 @@ int plugin_init(int *argc, char **argv, int flags) ...@@ -1401,8 +1415,10 @@ int plugin_init(int *argc, char **argv, int flags)
plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT) plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
reaped_mandatory_plugin= TRUE; reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true); plugin_deinitialize(plugin_ptr, true);
mysql_mutex_lock(&LOCK_plugin_delete);
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
plugin_del(plugin_ptr); plugin_del(plugin_ptr);
mysql_mutex_unlock(&LOCK_plugin_delete);
} }
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
...@@ -1692,10 +1708,11 @@ void plugin_shutdown(void) ...@@ -1692,10 +1708,11 @@ void plugin_shutdown(void)
} }
/* /*
It's perfectly safe not to lock LOCK_plugin, as there're no It's perfectly safe not to lock LOCK_plugin, LOCK_plugin_delete, as
concurrent threads anymore. But some functions called from here there're no concurrent threads anymore. But some functions called from
use mysql_mutex_assert_owner(), so we lock the mutex to satisfy it here use mysql_mutex_assert_owner(), so we lock the mutex to satisfy it
*/ */
mysql_mutex_lock(&LOCK_plugin_delete);
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
/* /*
...@@ -1718,9 +1735,11 @@ void plugin_shutdown(void) ...@@ -1718,9 +1735,11 @@ void plugin_shutdown(void)
cleanup_variables(NULL, &global_system_variables); cleanup_variables(NULL, &global_system_variables);
cleanup_variables(NULL, &max_system_variables); cleanup_variables(NULL, &max_system_variables);
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
mysql_mutex_unlock(&LOCK_plugin_delete);
initialized= 0; initialized= 0;
mysql_mutex_destroy(&LOCK_plugin); mysql_mutex_destroy(&LOCK_plugin);
mysql_mutex_destroy(&LOCK_plugin_delete);
my_afree(plugins); my_afree(plugins);
} }
...@@ -1795,6 +1814,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl ...@@ -1795,6 +1814,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS); mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
DEBUG_SYNC(thd, "acquired_LOCK_plugin");
mysql_rwlock_wrlock(&LOCK_system_variables_hash); mysql_rwlock_wrlock(&LOCK_system_variables_hash);
if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL)) if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
......
...@@ -40,6 +40,8 @@ extern const char *global_plugin_typelib_names[]; ...@@ -40,6 +40,8 @@ extern const char *global_plugin_typelib_names[];
#include <my_sys.h> #include <my_sys.h>
extern mysql_mutex_t LOCK_plugin_delete;
#ifdef DBUG_OFF #ifdef DBUG_OFF
#define plugin_ref_to_int(A) A #define plugin_ref_to_int(A) A
#define plugin_int_to_ref(A) A #define plugin_int_to_ref(A) A
......
...@@ -6292,6 +6292,7 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) ...@@ -6292,6 +6292,7 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
{ {
DBUG_ENTER("fill_variables"); DBUG_ENTER("fill_variables");
SHOW_VAR *sys_var_array;
int res= 0; int res= 0;
LEX *lex= thd->lex; LEX *lex= thd->lex;
const char *wild= lex->wild ? lex->wild->ptr() : NullS; const char *wild= lex->wild ? lex->wild->ptr() : NullS;
...@@ -6305,10 +6306,21 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) ...@@ -6305,10 +6306,21 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
schema_table_idx == SCH_GLOBAL_VARIABLES) schema_table_idx == SCH_GLOBAL_VARIABLES)
option_type= OPT_GLOBAL; option_type= OPT_GLOBAL;
/*
Lock LOCK_plugin_delete to avoid deletion of any plugins while creating
SHOW_VAR array and hold it until all variables are stored in the table.
*/
mysql_mutex_lock(&LOCK_plugin_delete);
// Lock LOCK_system_variables_hash to prepare SHOW_VARs array.
mysql_rwlock_rdlock(&LOCK_system_variables_hash); mysql_rwlock_rdlock(&LOCK_system_variables_hash);
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type), DEBUG_SYNC(thd, "acquired_LOCK_system_variables_hash");
option_type, NULL, "", tables->table, upper_case_names, cond); sys_var_array= enumerate_sys_vars(thd, sorted_vars, option_type);
mysql_rwlock_unlock(&LOCK_system_variables_hash); mysql_rwlock_unlock(&LOCK_system_variables_hash);
res= show_status_array(thd, wild, sys_var_array, option_type, NULL, "",
tables->table, upper_case_names, cond);
mysql_mutex_unlock(&LOCK_plugin_delete);
DBUG_RETURN(res); DBUG_RETURN(res);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment