Skip to content

Commit

Permalink
MDEV-10010 - Recursive call to mysql_rwlock_rdlock for LOCK_system_va…
Browse files Browse the repository at this point in the history
…riables_hash

Avoid recursive LOCK_system_variables_hash acquisition in
intern_sys_var_ptr() by pre-syncing dynamic session variables.
  • Loading branch information
Sergey Vojtovich committed Jul 8, 2016
1 parent 95c286c commit ecb27d2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 60 deletions.
125 changes: 65 additions & 60 deletions sql/sql_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,70 @@ static st_bookmark *register_var(const char *plugin, const char *name,
return result;
}


void sync_dynamic_session_variables(THD* thd, bool global_lock)
{
uint idx;

thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));

if (global_lock)
mysql_mutex_lock(&LOCK_global_system_variables);

mysql_mutex_assert_owner(&LOCK_global_system_variables);

memcpy(thd->variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_size -
thd->variables.dynamic_variables_size);

/*
now we need to iterate through any newly copied 'defaults'
and if it is a string type with MEMALLOC flag, we need to strdup
*/
for (idx= 0; idx < bookmark_hash.records; idx++)
{
sys_var_pluginvar *pi;
sys_var *var;
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);

if (v->version <= thd->variables.dynamic_variables_version)
continue; /* already in thd->variables */

if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pi= var->cast_pluginvar()) ||
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
continue;

/* Here we do anything special that may be required of the data types */

if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
{
int offset= ((thdvar_str_t *)(pi->plugin_var))->offset;
char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset);
if (*pp)
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
}
}

if (global_lock)
mysql_mutex_unlock(&LOCK_global_system_variables);

thd->variables.dynamic_variables_version=
global_system_variables.dynamic_variables_version;
thd->variables.dynamic_variables_head=
global_system_variables.dynamic_variables_head;
thd->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.
Expand All @@ -2976,67 +3040,8 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
if (!thd->variables.dynamic_variables_ptr ||
(uint)offset > thd->variables.dynamic_variables_head)
{
uint idx;

mysql_rwlock_rdlock(&LOCK_system_variables_hash);

thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));

if (global_lock)
mysql_mutex_lock(&LOCK_global_system_variables);

mysql_mutex_assert_owner(&LOCK_global_system_variables);

memcpy(thd->variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_size -
thd->variables.dynamic_variables_size);

/*
now we need to iterate through any newly copied 'defaults'
and if it is a string type with MEMALLOC flag, we need to strdup
*/
for (idx= 0; idx < bookmark_hash.records; idx++)
{
sys_var_pluginvar *pi;
sys_var *var;
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);

if (v->version <= thd->variables.dynamic_variables_version)
continue; /* already in thd->variables */

if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pi= var->cast_pluginvar()) ||
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
continue;

/* Here we do anything special that may be required of the data types */

if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
{
int offset= ((thdvar_str_t *)(pi->plugin_var))->offset;
char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset);
if (*pp)
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
}
}

if (global_lock)
mysql_mutex_unlock(&LOCK_global_system_variables);

thd->variables.dynamic_variables_version=
global_system_variables.dynamic_variables_version;
thd->variables.dynamic_variables_head=
global_system_variables.dynamic_variables_head;
thd->variables.dynamic_variables_size=
global_system_variables.dynamic_variables_size;

sync_dynamic_session_variables(thd, global_lock);
mysql_rwlock_unlock(&LOCK_system_variables_hash);
}
DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
Expand Down
1 change: 1 addition & 0 deletions sql/sql_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
plugin_foreach_func *func, void *arg);

extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
#endif
11 changes: 11 additions & 0 deletions sql/sql_show.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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),
scope, NULL, "", tables->table,
upper_case_names, partial_cond);
Expand Down

0 comments on commit ecb27d2

Please sign in to comment.