From 3a2ef059ca09ee98a582930de75c2b27ec116671 Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Fri, 28 Feb 2025 15:53:45 +0100 Subject: [PATCH] MDEV-37026 Fixes for wsrep provider options plugin The plugin didn't work with options given on the command line or config file. --- .../r/wsrep_provider_plugin_config.result | 24 ++++ .../wsrep/t/wsrep_provider_plugin_config.cnf | 26 +++++ .../wsrep/t/wsrep_provider_plugin_config.test | 14 +++ sql/wsrep_client_service.cc | 2 + sql/wsrep_client_service.h | 2 + sql/wsrep_mysqld.cc | 10 +- sql/wsrep_plugin.cc | 105 +++++++++++++++++- sql/wsrep_plugin.h | 8 +- sql/wsrep_server_state.cc | 6 +- wsrep-lib | 2 +- 10 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/wsrep/r/wsrep_provider_plugin_config.result create mode 100644 mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.cnf create mode 100644 mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.test diff --git a/mysql-test/suite/wsrep/r/wsrep_provider_plugin_config.result b/mysql-test/suite/wsrep/r/wsrep_provider_plugin_config.result new file mode 100644 index 0000000000000..175ac58f474b5 --- /dev/null +++ b/mysql-test/suite/wsrep/r/wsrep_provider_plugin_config.result @@ -0,0 +1,24 @@ +SHOW VARIABLES LIKE 'wsrep_provider_pc_npvo'; +Variable_name Value +wsrep_provider_pc_npvo ON +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'pc.npvo = [^;]+') AS provider_option; +provider_option +pc.npvo = true +SHOW VARIABLES LIKE 'wsrep_provider_repl_max_ws_size'; +Variable_name Value +wsrep_provider_repl_max_ws_size 1024 +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'repl.max_ws_size = [^;]+') AS provider_option; +provider_option +repl.max_ws_size = 1024 +SHOW VARIABLES LIKE 'wsrep_provider_evs_install_timeout'; +Variable_name Value +wsrep_provider_evs_install_timeout 8.100000 +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'evs.install_timeout = [^;]+') AS provider_option; +provider_option +evs.install_timeout = PT8.1S +SHOW VARIABLES LIKE 'wsrep_provider_gcache_size'; +Variable_name Value +wsrep_provider_gcache_size 10485760 +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'gcache.size = [^;]+') AS provider_option; +provider_option +gcache.size = 10M diff --git a/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.cnf b/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.cnf new file mode 100644 index 0000000000000..d7fbd502030cf --- /dev/null +++ b/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.cnf @@ -0,0 +1,26 @@ +!include include/default_my.cnf + +[mysqld.1] +wsrep-on=ON +wsrep-cluster-address=gcomm:// +wsrep-provider=@ENV.WSREP_PROVIDER +binlog-format=ROW +plugin-wsrep-provider=ON +wsrep-provider-base-port=@OPT.port + +# Test different type of options +wsrep-provider-gcache-size=1024 +wsrep-provider-pc-npvo=ON +wsrep-provider-evs-install-timeout=8.1 + +# Repeat same variable again +wsrep_provider_gcache_size=10M +wsrep_provider_pc_npvo=OFF +wsrep_provider_pc_npvo=ON + +# Option wsrep_provider_options can be used even if plugin-wsrep-provider +# is enabled. However, settings in wsrep_provider_options have lower +# precedence. For instance, the setting gcache.size below will +# be ignored because it was already set through provider options +# plugin above. +wsrep_provider_options='gcache.size=20M;repl.max_ws_size=1024' diff --git a/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.test b/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.test new file mode 100644 index 0000000000000..6a7fcfd53aaf0 --- /dev/null +++ b/mysql-test/suite/wsrep/t/wsrep_provider_plugin_config.test @@ -0,0 +1,14 @@ +--source include/have_wsrep.inc +--source include/have_innodb.inc + +SHOW VARIABLES LIKE 'wsrep_provider_pc_npvo'; +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'pc.npvo = [^;]+') AS provider_option; + +SHOW VARIABLES LIKE 'wsrep_provider_repl_max_ws_size'; +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'repl.max_ws_size = [^;]+') AS provider_option; + +SHOW VARIABLES LIKE 'wsrep_provider_evs_install_timeout'; +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'evs.install_timeout = [^;]+') AS provider_option; + +SHOW VARIABLES LIKE 'wsrep_provider_gcache_size'; +SELECT REGEXP_SUBSTR(@@wsrep_provider_options, 'gcache.size = [^;]+') AS provider_option; diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc index 222435f60639b..395acb23ae08c 100644 --- a/sql/wsrep_client_service.cc +++ b/sql/wsrep_client_service.cc @@ -393,3 +393,5 @@ int Wsrep_client_service::bf_rollback() DBUG_RETURN(ret); } + +void Wsrep_client_service::notify_state_change() {} diff --git a/sql/wsrep_client_service.h b/sql/wsrep_client_service.h index f53d9be083d72..f47ba3f11c851 100644 --- a/sql/wsrep_client_service.h +++ b/sql/wsrep_client_service.h @@ -68,6 +68,8 @@ class Wsrep_client_service : public wsrep::client_service void debug_sync(const char*) override; void debug_crash(const char*) override; int bf_rollback() override; + void notify_state_change() override; + private: friend class Wsrep_server_service; THD* m_thd; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index c0c29a0b85b9e..0424168f9dc6b 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -45,6 +45,7 @@ #include "wsrep_schema.h" #include "wsrep_xid.h" #include "wsrep_trans_observer.h" +#include "wsrep_plugin.h" /* wsrep_load_provider_plugin_defaults() */ #include "mysql/service_wsrep.h" #include #include @@ -897,9 +898,12 @@ int wsrep_init() Wsrep_server_state::init_provider_services(); if (Wsrep_server_state::instance().load_provider( - wsrep_provider, - wsrep_provider_options, - Wsrep_server_state::instance().provider_services())) + wsrep_provider, + [](const wsrep::provider_options &opts, std::string& defaults) { + defaults.append(wsrep_provider_options); + return wsrep_load_provider_plugin_defaults(opts, defaults); + }, + Wsrep_server_state::instance().provider_services())) { WSREP_ERROR("Failed to load provider"); Wsrep_server_state::deinit_provider_services(); diff --git a/sql/wsrep_plugin.cc b/sql/wsrep_plugin.cc index 644dc921f7092..a54cfa076e138 100644 --- a/sql/wsrep_plugin.cc +++ b/sql/wsrep_plugin.cc @@ -20,6 +20,7 @@ in favor of single options which are initialized from provider. */ +#include "wsrep_plugin.h" #include "sql_plugin.h" #include "sql_priv.h" #include "sql_class.h" @@ -131,7 +132,8 @@ static void wsrep_provider_sysvar_update(THD *thd, T new_value= *((T *) save); auto options= Wsrep_server_state::get_options(); - if (options->set(opt->name(), make_option_value(new_value))) + if (options->set(Wsrep_server_state::get_provider(), opt->name(), + make_option_value(new_value))) { my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), opt->name(), make_option_value(new_value)->as_string()); @@ -275,6 +277,107 @@ void wsrep_destroy_sysvar(struct st_mysql_sys_var *var) my_free(var); } +struct st_mysql_sys_var +{ + MYSQL_PLUGIN_VAR_HEADER; +}; + +struct my_option_arg +{ + wsrep::provider_options::option *option; + struct st_mysql_sys_var *sysvar; + std::string *defaults; +}; + +static void my_option_init(struct my_option &my_opt, + struct my_option_arg &my_arg) +{ + std::string option_name("wsrep-provider-"); + option_name.append(my_arg.sysvar->name); + for (size_t i= 0; i < option_name.size(); ++i) + if (option_name[i] == '_') + option_name[i]= '-'; + my_opt.name= my_strdup(PSI_INSTRUMENT_ME, option_name.c_str(), MYF(0)); + my_opt.id= 0; + plugin_opt_set_limits(&my_opt, my_arg.sysvar); + my_opt.value= my_opt.u_max_value= *(uchar ***) (my_arg.sysvar + 1); + my_opt.block_size= 0; + my_opt.app_type= &my_arg; +} + +static void my_option_deinit(struct my_option &my_opt) +{ + if (my_opt.name) + my_free((void*)my_opt.name); +} + +static void make_my_options(std::vector &my_args, + std::vector &my_options) +{ + for (auto& arg : my_args) + { + struct my_option my_opt; + my_option_init(my_opt, arg); + my_options.push_back(my_opt); + } + struct my_option null_opt; + null_opt.name= NULL; + my_options.push_back(null_opt); +} + +static void make_my_option_args(const wsrep::provider_options &options, + std::string &defaults, + std::vector &my_args) +{ + options.for_each([&](wsrep::provider_options::option *opt) { + my_args.push_back({opt, wsrep_make_sysvar_for_option(opt), &defaults}); + }); +} + +static my_bool option_changed(const struct my_option *opt, const char *value, + const char *filename) +{ + my_option_arg *my_arg= (struct my_option_arg *) opt->app_type; + if (my_arg->defaults->size()) + my_arg->defaults->append(";"); + my_arg->defaults->append(my_arg->option->real_name()); + my_arg->defaults->append("="); + my_arg->defaults->append(value); + return 0; +} + +int wsrep_load_provider_plugin_defaults(const wsrep::provider_options &options, + std::string &extra_options) +{ + int argc= orig_argc; + char **argv= orig_argv; + + if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv)) + { + return 1; + } + char **defaults_argv= argv; + + std::vector my_options; + std::vector my_option_args; + make_my_option_args(options, extra_options, my_option_args); + make_my_options(my_option_args, my_options); + + my_bool skip_unknown_orig= my_getopt_skip_unknown; + my_getopt_skip_unknown= TRUE; + int error= handle_options(&argc, &argv, &my_options[0], option_changed); + my_getopt_skip_unknown= skip_unknown_orig; + + for (struct my_option &opt : my_options) + my_option_deinit(opt); + for (struct my_option_arg &arg : my_option_args) + wsrep_destroy_sysvar(arg.sysvar); + if (argv) + free_defaults(defaults_argv); + + return error; +} + static int wsrep_provider_plugin_init(void *p) { WSREP_DEBUG("wsrep_provider_plugin_init()"); diff --git a/sql/wsrep_plugin.h b/sql/wsrep_plugin.h index 531d1d26a4850..14b7978f87b94 100644 --- a/sql/wsrep_plugin.h +++ b/sql/wsrep_plugin.h @@ -16,7 +16,8 @@ #ifndef WSREP_PLUGIN_H #define WSREP_PLUGIN_H -class option; +#include "wsrep/provider_options.hpp" + struct st_mysql_sys_var; /* Returns true if provider plugin was initialized and is active */ @@ -33,4 +34,9 @@ wsrep_make_sysvar_for_option(wsrep::provider_options::option *); /* Destroy a sysvar created by make_sysvar_for_option */ void wsrep_destroy_sysvar(struct st_mysql_sys_var *); +/* Parse defaults from config/command line, returns corresponding + provider options string */ +int wsrep_load_provider_plugin_defaults(const wsrep::provider_options &, + std::string &); + #endif /* WSREP_PLUGIN_H */ diff --git a/sql/wsrep_server_state.cc b/sql/wsrep_server_state.cc index 7bfe0d6c0815e..151565fcc0e98 100644 --- a/sql/wsrep_server_state.cc +++ b/sql/wsrep_server_state.cc @@ -99,9 +99,9 @@ int Wsrep_server_state::init_provider(const std::string& provider, int Wsrep_server_state::init_options() { if (!m_instance) return 1; - m_options= std::unique_ptr( - new wsrep::provider_options(m_instance->provider())); - int ret= m_options->initial_options(); + m_options= + std::unique_ptr(new wsrep::provider_options()); + int ret= m_options->initial_options(m_instance->provider()); if (ret) { WSREP_ERROR("Failed to initialize provider options"); diff --git a/wsrep-lib b/wsrep-lib index e55f01ce1eed0..b491197c587e1 160000 --- a/wsrep-lib +++ b/wsrep-lib @@ -1 +1 @@ -Subproject commit e55f01ce1eed02e0781bc53bb23456c936667ccf +Subproject commit b491197c587e16dcacc2af41a2d35da6a2d98330