Commit 8953c7e4 authored by Kristian Nielsen's avatar Kristian Nielsen

MDEV-12179: Per-engine mysql.gtid_slave_pos table

Intermediate commit.

Fix engine list lifetime for sys_var_pluginlist.

The Sys_var class assumes that some operations can be done without
explicitly freeing resources, for example default_value_ptr(). Thus,
methods (like Sys_var_pluginlist::do_check) need to generally work
with temporary lists, which are registered in the THD to be
freed/unlocked automatically. And do_update() needs to make a
permanent copy to store in the global variable.
parent 00eebb22
...@@ -4932,10 +4932,10 @@ init_gtid_pos_auto_engines(void) ...@@ -4932,10 +4932,10 @@ init_gtid_pos_auto_engines(void)
then it will certainly not be needed. then it will certainly not be needed.
*/ */
if (gtid_pos_auto_engines) if (gtid_pos_auto_engines)
plugins= resolve_engine_list(gtid_pos_auto_engines, plugins= resolve_engine_list(NULL, gtid_pos_auto_engines,
strlen(gtid_pos_auto_engines), false); strlen(gtid_pos_auto_engines), false, false);
else else
plugins= resolve_engine_list("", 0, false); plugins= resolve_engine_list(NULL, "", 0, false, false);
if (!plugins) if (!plugins)
return 1; return 1;
mysql_mutex_lock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_global_system_variables);
......
...@@ -1301,17 +1301,18 @@ engine_list_next_item(const char **pos, const char *end_pos, ...@@ -1301,17 +1301,18 @@ engine_list_next_item(const char **pos, const char *end_pos,
static bool static bool
resolve_engine_list_item(plugin_ref *list, uint32 *idx, resolve_engine_list_item(THD *thd, plugin_ref *list, uint32 *idx,
const char *pos, const char *pos_end, const char *pos, const char *pos_end,
bool error_on_unknown_engine) bool error_on_unknown_engine, bool temp_copy)
{ {
LEX_STRING item_str; LEX_STRING item_str;
plugin_ref ref; plugin_ref ref;
uint32_t i; uint32_t i;
THD *thd_or_null = (temp_copy ? thd : NULL);
item_str.str= const_cast<char*>(pos); item_str.str= const_cast<char*>(pos);
item_str.length= pos_end-pos; item_str.length= pos_end-pos;
ref= ha_resolve_by_name(NULL, &item_str, false); ref= ha_resolve_by_name(thd_or_null, &item_str, false);
if (!ref) if (!ref)
{ {
if (error_on_unknown_engine) if (error_on_unknown_engine)
...@@ -1327,6 +1328,7 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, ...@@ -1327,6 +1328,7 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx,
{ {
if (plugin_hton(list[i]) == plugin_hton(ref)) if (plugin_hton(list[i]) == plugin_hton(ref))
{ {
if (!temp_copy)
plugin_unlock(NULL, ref); plugin_unlock(NULL, ref);
return false; return false;
} }
...@@ -1341,10 +1343,16 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, ...@@ -1341,10 +1343,16 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx,
Helper for class Sys_var_pluginlist. Helper for class Sys_var_pluginlist.
Resolve a comma-separated list of storage engine names to a null-terminated Resolve a comma-separated list of storage engine names to a null-terminated
array of plugin_ref. array of plugin_ref.
If TEMP_COPY is true, a THD must be given as well. In this case, the
allocated memory and locked plugins are registered in the THD and will
be freed / unlocked automatically. If TEMP_COPY is true, THD can be
passed as NULL, and resources must be freed explicitly later with
free_engine_list().
*/ */
plugin_ref * plugin_ref *
resolve_engine_list(const char *str_arg, size_t str_arg_len, resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
bool error_on_unknown_engine) bool error_on_unknown_engine, bool temp_copy)
{ {
uint32 count, idx; uint32 count, idx;
const char *pos, *item_start, *item_end; const char *pos, *item_start, *item_end;
...@@ -1360,6 +1368,9 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len, ...@@ -1360,6 +1368,9 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len,
++count; ++count;
} }
if (temp_copy)
res= (plugin_ref *)thd->calloc((count+1)*sizeof(*res));
else
res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME));
if (!res) if (!res)
{ {
...@@ -1376,14 +1387,15 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len, ...@@ -1376,14 +1387,15 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len,
DBUG_ASSERT(idx < count); DBUG_ASSERT(idx < count);
if (idx >= count) if (idx >= count)
break; break;
if (resolve_engine_list_item(res, &idx, item_start, item_end, if (resolve_engine_list_item(thd, res, &idx, item_start, item_end,
error_on_unknown_engine)) error_on_unknown_engine, temp_copy))
goto err; goto err;
} }
return res; return res;
err: err:
if (!temp_copy)
free_engine_list(res); free_engine_list(res);
return NULL; return NULL;
} }
...@@ -1418,6 +1430,32 @@ copy_engine_list(plugin_ref *list) ...@@ -1418,6 +1430,32 @@ copy_engine_list(plugin_ref *list)
} }
for (i= 0; i < count; ++i) for (i= 0; i < count; ++i)
p[i]= my_plugin_lock(NULL, list[i]); p[i]= my_plugin_lock(NULL, list[i]);
p[i] = NULL;
return p;
}
/*
Create a temporary copy of an engine list. The memory will be freed
(and the plugins unlocked) automatically, on the passed THD.
*/
plugin_ref *
temp_copy_engine_list(THD *thd, plugin_ref *list)
{
plugin_ref *p;
uint32 count, i;
for (p= list, count= 0; *p; ++p, ++count)
;
p= (plugin_ref *)thd->alloc((count+1)*sizeof(*p));
if (!p)
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p)));
return NULL;
}
for (i= 0; i < count; ++i)
p[i]= my_plugin_lock(thd, list[i]);
p[i] = NULL;
return p; return p;
} }
......
...@@ -423,10 +423,11 @@ int sys_var_init(); ...@@ -423,10 +423,11 @@ int sys_var_init();
uint sys_var_elements(); uint sys_var_elements();
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
void sys_var_end(void); void sys_var_end(void);
plugin_ref *resolve_engine_list(const char *str_arg, size_t str_arg_len, plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
bool error_on_unknown_engine); bool error_on_unknown_engine, bool temp_copy);
void free_engine_list(plugin_ref *list); void free_engine_list(plugin_ref *list);
plugin_ref *copy_engine_list(plugin_ref *list); plugin_ref *copy_engine_list(plugin_ref *list);
plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list);
char *pretty_print_engine_list(THD *thd, plugin_ref *list); char *pretty_print_engine_list(THD *thd, plugin_ref *list);
#endif #endif
......
...@@ -3541,11 +3541,6 @@ check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var) ...@@ -3541,11 +3541,6 @@ check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var)
if (running) if (running)
err= true; err= true;
} }
if (err && var->save_result.plugins)
{
free_engine_list(var->save_result.plugins);
var->save_result.plugins= NULL;
}
return err; return err;
} }
......
...@@ -1546,6 +1546,17 @@ public: ...@@ -1546,6 +1546,17 @@ public:
These variables don't support command-line equivalents, any such These variables don't support command-line equivalents, any such
command-line options should be added manually to my_long_options in mysqld.cc command-line options should be added manually to my_long_options in mysqld.cc
Note on lifetimes of resources allocated: We allocate a zero-terminated array
of plugin_ref*, and lock the contained plugins. The list in the global
variable must be freed (with free_engine_list()). However, the way Sys_var
works, there is no place to explicitly free other lists, like the one
returned from get_default().
Therefore, the code needs to work with temporary lists, which are
registered in the THD to be automatically freed (and plugins similarly
automatically unlocked). This is why do_check() allocates a temporary
list, from which do_update() then makes a permanent copy.
*/ */
class Sys_var_pluginlist: public sys_var class Sys_var_pluginlist: public sys_var
{ {
...@@ -1575,9 +1586,9 @@ public: ...@@ -1575,9 +1586,9 @@ public:
plugin_ref *plugins; plugin_ref *plugins;
if (!(res=var->value->val_str(&str))) if (!(res=var->value->val_str(&str)))
plugins= resolve_engine_list("", 0, true); plugins= resolve_engine_list(thd, "", 0, true, true);
else else
plugins= resolve_engine_list(res->ptr(), res->length(), true); plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true);
if (!plugins) if (!plugins)
return true; return true;
var->save_result.plugins= plugins; var->save_result.plugins= plugins;
...@@ -1586,7 +1597,7 @@ public: ...@@ -1586,7 +1597,7 @@ public:
void do_update(plugin_ref **valptr, plugin_ref* newval) void do_update(plugin_ref **valptr, plugin_ref* newval)
{ {
plugin_ref *oldval= *valptr; plugin_ref *oldval= *valptr;
*valptr= newval; *valptr= copy_engine_list(newval);
free_engine_list(oldval); free_engine_list(oldval);
} }
bool session_update(THD *thd, set_var *var) bool session_update(THD *thd, set_var *var)
...@@ -1604,14 +1615,15 @@ public: ...@@ -1604,14 +1615,15 @@ public:
void session_save_default(THD *thd, set_var *var) void session_save_default(THD *thd, set_var *var)
{ {
plugin_ref* plugins= global_var(plugin_ref *); plugin_ref* plugins= global_var(plugin_ref *);
var->save_result.plugins= plugins ? copy_engine_list(plugins) : 0; var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0;
} }
plugin_ref *get_default(THD *thd) plugin_ref *get_default(THD *thd)
{ {
char *default_value= *reinterpret_cast<char**>(option.def_value); char *default_value= *reinterpret_cast<char**>(option.def_value);
if (!default_value) if (!default_value)
return 0; return 0;
return resolve_engine_list(default_value, strlen(default_value), false); return resolve_engine_list(thd, default_value, strlen(default_value),
false, true);
} }
void global_save_default(THD *thd, set_var *var) void global_save_default(THD *thd, set_var *var)
......
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