Commit ecb27d26 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-10010 - Recursive call to mysql_rwlock_rdlock for LOCK_system_variables_hash

Avoid recursive LOCK_system_variables_hash acquisition in
intern_sys_var_ptr() by pre-syncing dynamic session variables.
parent 95c286ce
...@@ -2955,31 +2955,11 @@ static st_bookmark *register_var(const char *plugin, const char *name, ...@@ -2955,31 +2955,11 @@ static st_bookmark *register_var(const char *plugin, const char *name,
return result; return result;
} }
/*
returns a pointer to the memory which holds the thd-local variable or
a pointer to the global variable if thd==null.
If required, will sync with global variables if the requested variable
has not yet been allocated in the current thread.
*/
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
{
DBUG_ENTER("intern_sys_var_ptr");
DBUG_ASSERT(offset >= 0);
DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);
if (!thd)
DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset);
/* void sync_dynamic_session_variables(THD* thd, bool global_lock)
dynamic_variables_head points to the largest valid offset {
*/
if (!thd->variables.dynamic_variables_ptr ||
(uint)offset > thd->variables.dynamic_variables_head)
{
uint idx; uint idx;
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
thd->variables.dynamic_variables_ptr= (char*) thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr, my_realloc(thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size, global_variables_dynamic_size,
...@@ -3036,7 +3016,32 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) ...@@ -3036,7 +3016,32 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
global_system_variables.dynamic_variables_head; global_system_variables.dynamic_variables_head;
thd->variables.dynamic_variables_size= thd->variables.dynamic_variables_size=
global_system_variables.dynamic_variables_size; global_system_variables.dynamic_variables_size;
}
/*
returns a pointer to the memory which holds the thd-local variable or
a pointer to the global variable if thd==null.
If required, will sync with global variables if the requested variable
has not yet been allocated in the current thread.
*/
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
{
DBUG_ENTER("intern_sys_var_ptr");
DBUG_ASSERT(offset >= 0);
DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);
if (!thd)
DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset);
/*
dynamic_variables_head points to the largest valid offset
*/
if (!thd->variables.dynamic_variables_ptr ||
(uint)offset > thd->variables.dynamic_variables_head)
{
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
sync_dynamic_session_variables(thd, global_lock);
mysql_rwlock_unlock(&LOCK_system_variables_hash); mysql_rwlock_unlock(&LOCK_system_variables_hash);
} }
DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
......
...@@ -190,4 +190,5 @@ extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, ...@@ -190,4 +190,5 @@ extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl, extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl,
plugin_foreach_func *func, void *arg); plugin_foreach_func *func, void *arg);
extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
#endif #endif
...@@ -7209,6 +7209,17 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) ...@@ -7209,6 +7209,17 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
COND *partial_cond= make_cond_for_info_schema(thd, cond, tables); COND *partial_cond= make_cond_for_info_schema(thd, cond, tables);
mysql_rwlock_rdlock(&LOCK_system_variables_hash); mysql_rwlock_rdlock(&LOCK_system_variables_hash);
/*
Avoid recursive LOCK_system_variables_hash acquisition in
intern_sys_var_ptr() by pre-syncing dynamic session variables.
*/
if (scope == OPT_SESSION &&
(!thd->variables.dynamic_variables_ptr ||
global_system_variables.dynamic_variables_head >
thd->variables.dynamic_variables_head))
sync_dynamic_session_variables(thd, true);
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, scope), res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, scope),
scope, NULL, "", tables->table, scope, NULL, "", tables->table,
upper_case_names, partial_cond); upper_case_names, partial_cond);
......
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