mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Bug#18903155: BACKPORT BUG-18008907 TO 5.5+ VERSIONS.
Backporting patch committed for bug 18008907 to 5.5 and 5.6.
This commit is contained in:
parent
70eca99172
commit
b2c2656b62
6 changed files with 227 additions and 6 deletions
|
@ -143,3 +143,73 @@ SELECT @@SESSION.example_double_thdvar;
|
|||
@@SESSION.example_double_thdvar
|
||||
1000.500000
|
||||
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;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#
|
||||
--source include/not_windows_embedded.inc
|
||||
--source include/have_example_plugin.inc
|
||||
--source include/have_debug_sync.inc
|
||||
|
||||
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
|
||||
DROP TABLE t1;
|
||||
|
@ -137,3 +139,118 @@ SET SESSION example_double_thdvar = 1000.51;
|
|||
SELECT @@SESSION.example_double_thdvar;
|
||||
|
||||
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
|
||||
|
|
0
scripts/mysqlaccess.conf
Normal file → Executable file
0
scripts/mysqlaccess.conf
Normal file → Executable file
|
@ -33,6 +33,7 @@
|
|||
#include "sql_audit.h"
|
||||
#include <mysql/plugin_auth.h>
|
||||
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
|
||||
#include "debug_sync.h"
|
||||
#define REPORT_TO_LOG 1
|
||||
#define REPORT_TO_USER 2
|
||||
|
||||
|
@ -131,6 +132,12 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
|
|||
|
||||
#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
|
||||
following variables/structures.
|
||||
|
@ -949,6 +956,7 @@ static void plugin_del(struct st_plugin_int *plugin)
|
|||
{
|
||||
DBUG_ENTER("plugin_del(plugin)");
|
||||
mysql_mutex_assert_owner(&LOCK_plugin);
|
||||
mysql_mutex_assert_owner(&LOCK_plugin_delete);
|
||||
/* Free allocated strings before deleting the plugin. */
|
||||
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
|
||||
mysql_del_sys_var_chain(plugin->system_vars);
|
||||
|
@ -996,11 +1004,14 @@ static void reap_plugins(void)
|
|||
while ((plugin= *(--list)))
|
||||
plugin_deinitialize(plugin, true);
|
||||
|
||||
mysql_mutex_lock(&LOCK_plugin_delete);
|
||||
mysql_mutex_lock(&LOCK_plugin);
|
||||
|
||||
while ((plugin= *(--reap)))
|
||||
plugin_del(plugin);
|
||||
|
||||
mysql_mutex_unlock(&LOCK_plugin_delete);
|
||||
|
||||
my_afree(reap);
|
||||
}
|
||||
|
||||
|
@ -1205,10 +1216,12 @@ static inline void convert_underscore_to_dash(char *str, int len)
|
|||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
static PSI_mutex_key key_LOCK_plugin;
|
||||
static PSI_mutex_key key_LOCK_plugin_delete;
|
||||
|
||||
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)
|
||||
|
@ -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_delete, &LOCK_plugin_delete, MY_MUTEX_INIT_FAST);
|
||||
|
||||
if (my_init_dynamic_array(&plugin_dl_array,
|
||||
sizeof(struct st_plugin_dl *),16,16) ||
|
||||
|
@ -1401,8 +1415,10 @@ int plugin_init(int *argc, char **argv, int flags)
|
|||
plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
|
||||
reaped_mandatory_plugin= TRUE;
|
||||
plugin_deinitialize(plugin_ptr, true);
|
||||
mysql_mutex_lock(&LOCK_plugin_delete);
|
||||
mysql_mutex_lock(&LOCK_plugin);
|
||||
plugin_del(plugin_ptr);
|
||||
mysql_mutex_unlock(&LOCK_plugin_delete);
|
||||
}
|
||||
|
||||
mysql_mutex_unlock(&LOCK_plugin);
|
||||
|
@ -1692,10 +1708,11 @@ void plugin_shutdown(void)
|
|||
}
|
||||
|
||||
/*
|
||||
It's perfectly safe not to lock LOCK_plugin, as there're no
|
||||
concurrent threads anymore. But some functions called from here
|
||||
use mysql_mutex_assert_owner(), so we lock the mutex to satisfy it
|
||||
It's perfectly safe not to lock LOCK_plugin, LOCK_plugin_delete, as
|
||||
there're no concurrent threads anymore. But some functions called from
|
||||
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);
|
||||
|
||||
/*
|
||||
|
@ -1718,9 +1735,11 @@ void plugin_shutdown(void)
|
|||
cleanup_variables(NULL, &global_system_variables);
|
||||
cleanup_variables(NULL, &max_system_variables);
|
||||
mysql_mutex_unlock(&LOCK_plugin);
|
||||
mysql_mutex_unlock(&LOCK_plugin_delete);
|
||||
|
||||
initialized= 0;
|
||||
mysql_mutex_destroy(&LOCK_plugin);
|
||||
mysql_mutex_destroy(&LOCK_plugin_delete);
|
||||
|
||||
my_afree(plugins);
|
||||
}
|
||||
|
@ -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_mutex_lock(&LOCK_plugin);
|
||||
DEBUG_SYNC(thd, "acquired_LOCK_plugin");
|
||||
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
|
||||
|
||||
if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
|
||||
|
|
|
@ -40,6 +40,8 @@ extern const char *global_plugin_typelib_names[];
|
|||
|
||||
#include <my_sys.h>
|
||||
|
||||
extern mysql_mutex_t LOCK_plugin_delete;
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
#define plugin_ref_to_int(A) A
|
||||
#define plugin_int_to_ref(A) A
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
DBUG_ENTER("fill_variables");
|
||||
SHOW_VAR *sys_var_array;
|
||||
int res= 0;
|
||||
LEX *lex= thd->lex;
|
||||
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
|
||||
|
@ -6305,10 +6306,21 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
schema_table_idx == SCH_GLOBAL_VARIABLES)
|
||||
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);
|
||||
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
|
||||
option_type, NULL, "", tables->table, upper_case_names, cond);
|
||||
DEBUG_SYNC(thd, "acquired_LOCK_system_variables_hash");
|
||||
sys_var_array= enumerate_sys_vars(thd, sorted_vars, option_type);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue