From 363d6a16ae3469496e9f17eab168c5b14fad7203 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Mon, 20 Mar 2017 11:55:24 +0100 Subject: MDEV-12179: Per-engine mysql.gtid_slave_pos table Intermediate commit. Implement a --gtid-pos-auto-engines system variable. The variable is a list of engines for which mysql.gtid_slave_pos_ENGINE should be auto-created if needed. This commit only implements the option variable. It is not yet used to actually auto-create any tables, nor is there a corresponding command-line version of the option yet. --- sql/set_var.cc | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) (limited to 'sql/set_var.cc') diff --git a/sql/set_var.cc b/sql/set_var.cc index 07395e3e708..7b190f6244e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1278,3 +1278,177 @@ enum sys_var::where get_sys_var_value_origin(void *ptr) return sys_var::CONFIG; } + +/* + Find the next item in string of comma-separated items. + END_POS points at the end of the string. + ITEM_START and ITEM_END return the limits of the next item. + Returns true while items are available, false at the end. +*/ +static bool +engine_list_next_item(const char **pos, const char *end_pos, + const char **item_start, const char **item_end) +{ + if (*pos >= end_pos) + return false; + *item_start= *pos; + while (*pos < end_pos && **pos != ',') + ++*pos; + *item_end= *pos; + ++*pos; + return true; +} + + +static bool +resolve_engine_list_item(plugin_ref *list, uint32 *idx, + const char *pos, const char *pos_end) +{ + LEX_STRING item_str; + plugin_ref ref; + uint32_t i; + + item_str.str= const_cast(pos); + item_str.length= pos_end-pos; + ref= ha_resolve_by_name(NULL, &item_str, false); + if (!ref) + { + ErrConvString err(pos, pos_end-pos, system_charset_info); + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); + return true; + } + /* Ignore duplicates, like --plugin-load does. */ + for (i= 0; i < *idx; ++i) + { + if (plugin_hton(list[i]) == plugin_hton(ref)) + { + plugin_unlock(NULL, ref); + return false; + } + } + list[*idx]= ref; + ++*idx; + return false; +} + + +/* + Helper for class Sys_var_pluginlist. + Resolve a comma-separated list of storage engine names to a null-terminated + array of plugin_ref. +*/ +plugin_ref * +resolve_engine_list(const char *str_arg, size_t str_arg_len) +{ + uint32 count, idx; + const char *pos, *item_start, *item_end; + const char *str_arg_end= str_arg + str_arg_len; + plugin_ref *res; + + count= 0; + pos= str_arg; + for (;;) + { + if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end)) + break; + ++count; + } + + res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); + if (!res) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res))); + goto err; + } + + idx= 0; + pos= str_arg; + for (;;) + { + if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end)) + break; + DBUG_ASSERT(idx < count); + if (idx >= count) + break; + if (resolve_engine_list_item(res, &idx, item_start, item_end)) + goto err; + } + + return res; + +err: + free_engine_list(res); + return NULL; +} + + +void +free_engine_list(plugin_ref *list) +{ + plugin_ref *p; + + if (!list) + return; + for (p= list; *p; ++p) + plugin_unlock(NULL, *p); + my_free(list); +} + + +plugin_ref * +copy_engine_list(plugin_ref *list) +{ + plugin_ref *p; + uint32 count, i; + + for (p= list, count= 0; *p; ++p, ++count) + ; + p= (plugin_ref *)my_malloc((count+1)*sizeof(*p), MYF(0)); + 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(NULL, list[i]); + return p; +} + + +char * +pretty_print_engine_list(THD *thd, plugin_ref *list) +{ + plugin_ref *p; + size_t size; + char *buf, *pos; + + if (!list) + return thd->strmake("", 0); + + size= 0; + for (p= list; *p; ++p) + size+= plugin_name(*p)->length + 1; + buf= static_cast(thd->alloc(size)); + if (!buf) + return NULL; + pos= buf; + for (p= list; *p; ++p) + { + LEX_STRING *name; + size_t remain; + + remain= buf + size - pos; + DBUG_ASSERT(remain > 0); + if (remain <= 1) + break; + if (pos != buf) + { + pos= strmake(pos, ",", remain-1); + --remain; + } + name= plugin_name(*p); + pos= strmake(pos, name->str, MY_MIN(name->length, remain-1)); + } + *pos= '\0'; + return buf; +} -- cgit v1.2.1 From 3cc89b3e85605ecb09b4b2222c8b0b8222a29fde Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Fri, 24 Mar 2017 12:06:29 +0100 Subject: MDEV-12179: Per-engine mysql.gtid_slave_pos table Intermediate commit. Ignore unknown engines in --gtid-pos-auto-engines command-line options (but not SET GLOBAL). This seems useful, to allow a default that auto-creates the gtid pos table for engines like TokuDB and MyRocks (which greatly benefit from such), but does not prevent server startup when those engines are not available. --- sql/set_var.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'sql/set_var.cc') diff --git a/sql/set_var.cc b/sql/set_var.cc index 7b190f6244e..78904f75661 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1302,7 +1302,8 @@ engine_list_next_item(const char **pos, const char *end_pos, static bool resolve_engine_list_item(plugin_ref *list, uint32 *idx, - const char *pos, const char *pos_end) + const char *pos, const char *pos_end, + bool error_on_unknown_engine) { LEX_STRING item_str; plugin_ref ref; @@ -1313,9 +1314,13 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, ref= ha_resolve_by_name(NULL, &item_str, false); if (!ref) { - ErrConvString err(pos, pos_end-pos, system_charset_info); - my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); - return true; + if (error_on_unknown_engine) + { + ErrConvString err(pos, pos_end-pos, system_charset_info); + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); + return true; + } + return false; } /* Ignore duplicates, like --plugin-load does. */ for (i= 0; i < *idx; ++i) @@ -1338,7 +1343,8 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, array of plugin_ref. */ plugin_ref * -resolve_engine_list(const char *str_arg, size_t str_arg_len) +resolve_engine_list(const char *str_arg, size_t str_arg_len, + bool error_on_unknown_engine) { uint32 count, idx; const char *pos, *item_start, *item_end; @@ -1370,7 +1376,8 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len) DBUG_ASSERT(idx < count); if (idx >= count) break; - if (resolve_engine_list_item(res, &idx, item_start, item_end)) + if (resolve_engine_list_item(res, &idx, item_start, item_end, + error_on_unknown_engine)) goto err; } -- cgit v1.2.1 From 8953c7e48426671f8fb3a68cae22eb7a00cfee61 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Thu, 20 Apr 2017 16:19:01 +0200 Subject: 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. --- sql/set_var.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 10 deletions(-) (limited to 'sql/set_var.cc') diff --git a/sql/set_var.cc b/sql/set_var.cc index 78904f75661..acc744808cb 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1301,17 +1301,18 @@ engine_list_next_item(const char **pos, const char *end_pos, 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, - bool error_on_unknown_engine) + bool error_on_unknown_engine, bool temp_copy) { LEX_STRING item_str; plugin_ref ref; uint32_t i; + THD *thd_or_null = (temp_copy ? thd : NULL); item_str.str= const_cast(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 (error_on_unknown_engine) @@ -1327,7 +1328,8 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, { if (plugin_hton(list[i]) == plugin_hton(ref)) { - plugin_unlock(NULL, ref); + if (!temp_copy) + plugin_unlock(NULL, ref); return false; } } @@ -1341,10 +1343,16 @@ resolve_engine_list_item(plugin_ref *list, uint32 *idx, Helper for class Sys_var_pluginlist. Resolve a comma-separated list of storage engine names to a null-terminated 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 * -resolve_engine_list(const char *str_arg, size_t str_arg_len, - bool error_on_unknown_engine) +resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len, + bool error_on_unknown_engine, bool temp_copy) { uint32 count, idx; const char *pos, *item_start, *item_end; @@ -1360,7 +1368,10 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len, ++count; } - res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); + 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)); if (!res) { my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res))); @@ -1376,15 +1387,16 @@ resolve_engine_list(const char *str_arg, size_t str_arg_len, DBUG_ASSERT(idx < count); if (idx >= count) break; - if (resolve_engine_list_item(res, &idx, item_start, item_end, - error_on_unknown_engine)) + if (resolve_engine_list_item(thd, res, &idx, item_start, item_end, + error_on_unknown_engine, temp_copy)) goto err; } return res; err: - free_engine_list(res); + if (!temp_copy) + free_engine_list(res); return NULL; } @@ -1418,6 +1430,32 @@ copy_engine_list(plugin_ref *list) } for (i= 0; i < count; ++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; } -- cgit v1.2.1