summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Vojtovich <svoj@mariadb.org>2016-06-27 15:01:22 +0400
committerSergey Vojtovich <svoj@mariadb.org>2016-07-08 23:38:05 +0400
commitecb27d2650da546c53bf7ff709cc6bf5bfa7f289 (patch)
tree64b9e34560c78468837c43c7c2333c1cc556e40b
parent95c286cedf4b9330240a0a91a9fc3e58a17782b9 (diff)
downloadmariadb-git-ecb27d2650da546c53bf7ff709cc6bf5bfa7f289.tar.gz
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.
-rw-r--r--sql/sql_plugin.cc125
-rw-r--r--sql/sql_plugin.h1
-rw-r--r--sql/sql_show.cc11
3 files changed, 77 insertions, 60 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 0158ab7d206..850d44f83e3 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -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.
@@ -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);
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index efa48b22ce8..9483fc8d9b3 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -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
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8ec44bad966..ae3874506dd 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -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);