mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
cleanup: wsrep_check_opts
This commit is contained in:
@@ -4142,15 +4142,6 @@ static int init_common_variables()
|
||||
SQLCOM_END + 8);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
/*
|
||||
This is a protection against mutually incompatible option values.
|
||||
Note WSREP_ON == global_system_variables.wsrep_on
|
||||
*/
|
||||
if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv))
|
||||
global_system_variables.wsrep_on= 0;
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
if (get_options(&remaining_argc, &remaining_argv))
|
||||
return 1;
|
||||
set_server_version();
|
||||
@@ -4990,6 +4981,9 @@ a file name for --log-bin-index option", opt_binlog_index_name);
|
||||
}
|
||||
plugins_are_initialized= TRUE; /* Don't separate from init function */
|
||||
|
||||
if (wsrep_check_opts())
|
||||
unireg_abort(1);
|
||||
|
||||
/* we do want to exit if there are any other unknown options */
|
||||
if (remaining_argc > 1)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2011 Codership Oy <http://www.codership.com>
|
||||
Copyright 2014 SkySQL Ab.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -13,367 +14,89 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
//#include <mysqld.h>
|
||||
#include <sql_class.h>
|
||||
//#include <sql_plugin.h>
|
||||
//#include <set_var.h>
|
||||
#include "mysqld.h"
|
||||
#include "sys_vars_shared.h"
|
||||
#include "wsrep.h"
|
||||
#include "wsrep_sst.h"
|
||||
//#include <sql_class.h>
|
||||
//#include "wsrep_mysqld.h"
|
||||
|
||||
#include "wsrep_mysqld.h"
|
||||
extern char *my_bind_addr_str;
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* This file is about checking for correctness of mysql configuration options */
|
||||
|
||||
struct opt
|
||||
int wsrep_check_opts()
|
||||
{
|
||||
const char* const name;
|
||||
const char* value;
|
||||
};
|
||||
|
||||
/* A list of options to check.
|
||||
* At first we assume default values and then see if they are changed on CLI or
|
||||
* in my.cnf */
|
||||
static struct opt opts[] =
|
||||
{
|
||||
{ "wsrep_slave_threads", "1" }, // mysqld.cc
|
||||
{ "bind_address", "0.0.0.0" }, // mysqld.cc
|
||||
{ "wsrep_sst_method", "rsync" }, // mysqld.cc
|
||||
{ "wsrep_sst_receive_address","AUTO"}, // mysqld.cc
|
||||
{ "binlog_format", "ROW" }, // mysqld.cc
|
||||
{ "wsrep_provider", "none" }, // mysqld.cc
|
||||
{ "query_cache_type", "0" }, // mysqld.cc
|
||||
{ "query_cache_size", "0" }, // mysqld.cc
|
||||
{ "locked_in_memory", "0" }, // mysqld.cc
|
||||
{ "wsrep_cluster_address", "0" }, // mysqld.cc
|
||||
{ "locks_unsafe_for_binlog", "0" }, // ha_innodb.cc
|
||||
{ "autoinc_lock_mode", "1" }, // ha_innodb.cc
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WSREP_SLAVE_THREADS,
|
||||
BIND_ADDRESS,
|
||||
WSREP_SST_METHOD,
|
||||
WSREP_SST_RECEIVE_ADDRESS,
|
||||
BINLOG_FORMAT,
|
||||
WSREP_PROVIDER,
|
||||
QUERY_CACHE_TYPE,
|
||||
QUERY_CACHE_SIZE,
|
||||
LOCKED_IN_MEMORY,
|
||||
WSREP_CLUSTER_ADDRESS,
|
||||
LOCKS_UNSAFE_FOR_BINLOG,
|
||||
AUTOINC_LOCK_MODE
|
||||
};
|
||||
|
||||
|
||||
/* A class to make a copy of argv[] vector */
|
||||
struct argv_copy
|
||||
{
|
||||
int const argc_;
|
||||
char** argv_;
|
||||
|
||||
argv_copy (int const argc, const char* const argv[]) :
|
||||
argc_ (argc),
|
||||
argv_ (reinterpret_cast<char**>(calloc(argc_, sizeof(char*))))
|
||||
if (wsrep_slave_threads > 1)
|
||||
{
|
||||
sys_var *autoinc_lock_mode=
|
||||
intern_find_sys_var(STRING_WITH_LEN("innodb_autoinc_lock_mode"));
|
||||
bool is_null;
|
||||
if (autoinc_lock_mode &&
|
||||
autoinc_lock_mode->val_int(&is_null, 0, OPT_GLOBAL, 0) != 2)
|
||||
{
|
||||
if (argv_)
|
||||
{
|
||||
for (int i = 0; i < argc_; ++i)
|
||||
{
|
||||
argv_[i] = strdup(argv[i]);
|
||||
|
||||
if (!argv_[i])
|
||||
{
|
||||
argv_free (); // free whatever bee allocated
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
WSREP_ERROR("Parallel applying (wsrep_slave_threads > 1) requires"
|
||||
" innodb_autoinc_lock_mode = 2.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
~argv_copy () { argv_free (); }
|
||||
|
||||
private:
|
||||
argv_copy (const argv_copy&);
|
||||
argv_copy& operator= (const argv_copy&);
|
||||
|
||||
void argv_free()
|
||||
{
|
||||
if (argv_)
|
||||
{
|
||||
for (int i = 0; (i < argc_) && argv_[i] ; ++i) free (argv_[i]);
|
||||
free (argv_);
|
||||
argv_ = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* a short corresponding to '--' byte sequence */
|
||||
static short const long_opt_prefix ('-' + ('-' << 8));
|
||||
|
||||
/* Normalizes long options to have '_' instead of '-' */
|
||||
static int
|
||||
normalize_opts (argv_copy& a)
|
||||
{
|
||||
if (a.argv_)
|
||||
{
|
||||
for (int i = 0; i < a.argc_; ++i)
|
||||
{
|
||||
char* ptr = a.argv_[i];
|
||||
if (long_opt_prefix == *(short*)ptr) // long option
|
||||
{
|
||||
ptr += 2;
|
||||
const char* end = strchr(ptr, '=');
|
||||
|
||||
if (!end) end = ptr + strlen(ptr);
|
||||
|
||||
for (; ptr != end; ++ptr) if ('-' == *ptr) *ptr = '_';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Find required options in the argument list and change their values */
|
||||
static int
|
||||
find_opts (argv_copy& a, struct opt* const opts)
|
||||
{
|
||||
for (int i = 0; i < a.argc_; ++i)
|
||||
{
|
||||
char* ptr = a.argv_[i] + 2; // we're interested only in long options
|
||||
|
||||
struct opt* opt = opts;
|
||||
for (; 0 != opt->name; ++opt)
|
||||
{
|
||||
if (!strstr(ptr, opt->name)) continue; // try next option
|
||||
|
||||
/* 1. try to find value after the '=' */
|
||||
opt->value = strchr(ptr, '=') + 1;
|
||||
|
||||
/* 2. if no '=', try next element in the argument vector */
|
||||
if (reinterpret_cast<void*>(1) == opt->value)
|
||||
{
|
||||
/* also check that the next element is not an option itself */
|
||||
if (i + 1 < a.argc_ && *(a.argv_[i + 1]) != '-')
|
||||
{
|
||||
++i;
|
||||
opt->value = a.argv_[i];
|
||||
}
|
||||
else opt->value = ""; // no value supplied (like boolean opt)
|
||||
}
|
||||
|
||||
break; // option found, break inner loop
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parses string for an integer. Returns 0 on success. */
|
||||
int get_long_long (const struct opt& opt, long long* const val, int const base)
|
||||
{
|
||||
const char* const str = opt.value;
|
||||
|
||||
if ('\0' != *str)
|
||||
{
|
||||
char* endptr;
|
||||
|
||||
*val = strtoll (str, &endptr, base);
|
||||
|
||||
if ('k' == *endptr || 'K' == *endptr)
|
||||
{
|
||||
*val *= 1024L;
|
||||
endptr++;
|
||||
}
|
||||
else if ('m' == *endptr || 'M' == *endptr)
|
||||
{
|
||||
*val *= 1024L * 1024L;
|
||||
endptr++;
|
||||
}
|
||||
else if ('g' == *endptr || 'G' == *endptr)
|
||||
{
|
||||
*val *= 1024L * 1024L * 1024L;
|
||||
endptr++;
|
||||
}
|
||||
|
||||
if ('\0' == *endptr) return 0; // the whole string was a valid integer
|
||||
}
|
||||
|
||||
WSREP_ERROR ("Bad value for *%s: '%s'. Should be integer.",
|
||||
opt.name, opt.value);
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* This is flimzy coz hell knows how mysql interprets boolean strings...
|
||||
* and, no, I'm not going to become versed in how mysql handles options -
|
||||
* I'd rather sing.
|
||||
|
||||
Aha, http://dev.mysql.com/doc/refman/5.1/en/dynamic-system-variables.html:
|
||||
Variables that have a type of “boolean” can be set to 0, 1, ON or OFF. (If you
|
||||
set them on the command line or in an option file, use the numeric values.)
|
||||
|
||||
So it is '0' for FALSE, '1' or empty string for TRUE
|
||||
|
||||
*/
|
||||
int get_bool (const struct opt& opt, bool* const val)
|
||||
{
|
||||
const char* str = opt.value;
|
||||
|
||||
while (isspace(*str)) ++str; // skip initial whitespaces
|
||||
|
||||
ssize_t str_len = strlen(str);
|
||||
switch (str_len)
|
||||
{
|
||||
case 0:
|
||||
*val = true;
|
||||
return 0;
|
||||
case 1:
|
||||
if ('0' == *str || '1' == *str)
|
||||
{
|
||||
*val = ('1' == *str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
WSREP_ERROR ("Bad value for *%s: '%s'. Should be '0', '1' or empty string.",
|
||||
opt.name, opt.value);
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
check_opts (int const argc, const char* const argv[], struct opt opts[])
|
||||
{
|
||||
/* First, make a copy of argv to be able to manipulate it */
|
||||
argv_copy a(argc, argv);
|
||||
|
||||
if (!a.argv_)
|
||||
{
|
||||
WSREP_ERROR ("Could not copy argv vector: not enough memory.");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
int err = normalize_opts (a);
|
||||
if (err)
|
||||
{
|
||||
WSREP_ERROR ("Failed to normalize options.");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = find_opts (a, opts);
|
||||
if (err)
|
||||
{
|
||||
WSREP_ERROR ("Failed to parse options.");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* At this point we have updated default values in our option list to
|
||||
what has been specified on the command line / my.cnf */
|
||||
|
||||
long long slave_threads;
|
||||
err = get_long_long (opts[WSREP_SLAVE_THREADS], &slave_threads, 10);
|
||||
if (err) return err;
|
||||
|
||||
int rcode = 0;
|
||||
|
||||
if (slave_threads > 1)
|
||||
/* Need to check AUTOINC_LOCK_MODE and LOCKS_UNSAFE_FOR_BINLOG */
|
||||
{
|
||||
long long autoinc_lock_mode;
|
||||
err = get_long_long (opts[AUTOINC_LOCK_MODE], &autoinc_lock_mode, 10);
|
||||
if (err) return err;
|
||||
|
||||
bool locks_unsafe_for_binlog;
|
||||
err = get_bool (opts[LOCKS_UNSAFE_FOR_BINLOG],&locks_unsafe_for_binlog);
|
||||
if (err) return err;
|
||||
|
||||
if (autoinc_lock_mode != 2)
|
||||
{
|
||||
WSREP_ERROR ("Parallel applying (wsrep_slave_threads > 1) requires"
|
||||
" innodb_autoinc_lock_mode = 2.");
|
||||
rcode = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
bool locked_in_memory;
|
||||
err = get_bool (opts[LOCKED_IN_MEMORY], &locked_in_memory);
|
||||
if (err) { WSREP_ERROR("get_bool error: %s", strerror(err)); return err; }
|
||||
if (locked_in_memory)
|
||||
{
|
||||
WSREP_ERROR ("Memory locking is not supported (locked_in_memory=%s)",
|
||||
locked_in_memory ? "ON" : "OFF");
|
||||
rcode = EINVAL;
|
||||
WSREP_ERROR("Memory locking is not supported (locked_in_memory=ON)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcasecmp(opts[WSREP_SST_METHOD].value,"mysqldump"))
|
||||
if (!strcasecmp(wsrep_sst_method, "mysqldump"))
|
||||
{
|
||||
if (!strcasecmp(opts[BIND_ADDRESS].value, "127.0.0.1") ||
|
||||
!strcasecmp(opts[BIND_ADDRESS].value, "localhost"))
|
||||
{
|
||||
WSREP_ERROR ("wsrep_sst_method is set to 'mysqldump' yet "
|
||||
"mysqld bind_address is set to '%s', which makes it "
|
||||
"impossible to receive state transfer from another "
|
||||
"node, since mysqld won't accept such connections. "
|
||||
"If you wish to use mysqldump state transfer method, "
|
||||
"set bind_address to allow mysql client connections "
|
||||
"from other cluster members (e.g. 0.0.0.0).",
|
||||
opts[BIND_ADDRESS].value);
|
||||
rcode = EINVAL;
|
||||
}
|
||||
if (!strcasecmp(my_bind_addr_str, "127.0.0.1") ||
|
||||
!strcasecmp(my_bind_addr_str, "localhost"))
|
||||
{
|
||||
WSREP_ERROR("wsrep_sst_method is set to 'mysqldump' yet "
|
||||
"mysqld bind_address is set to '%s', which makes it "
|
||||
"impossible to receive state transfer from another "
|
||||
"node, since mysqld won't accept such connections. "
|
||||
"If you wish to use mysqldump state transfer method, "
|
||||
"set bind_address to allow mysql client connections "
|
||||
"from other cluster members (e.g. 0.0.0.0).",
|
||||
my_bind_addr_str);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-mysqldump SST requires wsrep_cluster_address on startup
|
||||
if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0)
|
||||
{
|
||||
WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be "
|
||||
"configured on startup.",opts[WSREP_SST_METHOD].value);
|
||||
rcode = EINVAL;
|
||||
}
|
||||
// non-mysqldump SST requires wsrep_cluster_address on startup
|
||||
if (!wsrep_cluster_address || !wsrep_cluster_address[0])
|
||||
{
|
||||
WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be "
|
||||
"configured on startup.", wsrep_sst_method);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, "AUTO"))
|
||||
if (strcasecmp(wsrep_sst_receive_address, "AUTO"))
|
||||
{
|
||||
if (!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value,
|
||||
"127.0.0.1", strlen("127.0.0.1")) ||
|
||||
!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value,
|
||||
"localhost", strlen("localhost")))
|
||||
{
|
||||
WSREP_WARN ("wsrep_sst_receive_address is set to '%s' which "
|
||||
"makes it impossible for another host to reach this "
|
||||
"one. Please set it to the address which this node "
|
||||
"can be connected at by other cluster members.",
|
||||
opts[WSREP_SST_RECEIVE_ADDRESS].value);
|
||||
// rcode = EINVAL;
|
||||
}
|
||||
if (!strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("127.0.0.1")) ||
|
||||
!strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("localhost")))
|
||||
{
|
||||
WSREP_WARN("wsrep_sst_receive_address is set to '%s' which "
|
||||
"makes it impossible for another host to reach this "
|
||||
"one. Please set it to the address which this node "
|
||||
"can be connected at by other cluster members.",
|
||||
wsrep_sst_receive_address);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp(opts[WSREP_PROVIDER].value, "none"))
|
||||
if (strcasecmp(wsrep_provider, "NONE"))
|
||||
{
|
||||
if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW"))
|
||||
{
|
||||
WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. "
|
||||
"Configured value: '%s'. Please adjust your "
|
||||
"configuration.", opts[BINLOG_FORMAT].value);
|
||||
if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW)
|
||||
{
|
||||
WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. "
|
||||
"Configured value: '%s'. Please adjust your "
|
||||
"configuration.",
|
||||
binlog_format_names[global_system_variables.binlog_format]);
|
||||
|
||||
rcode = EINVAL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int
|
||||
wsrep_check_opts (int const argc, char* const* const argv)
|
||||
{
|
||||
return check_opts (argc, argv, opts);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,8 +152,8 @@ extern void wsrep_kill_mysql(THD *thd);
|
||||
/* new defines */
|
||||
extern void wsrep_stop_replication(THD *thd);
|
||||
extern bool wsrep_start_replication();
|
||||
extern bool wsrep_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
|
||||
extern int wsrep_check_opts (int argc, char* const* argv);
|
||||
extern bool wsrep_sync_wait(THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
|
||||
extern int wsrep_check_opts();
|
||||
extern void wsrep_prepend_PATH (const char* path);
|
||||
/* some inline functions are defined in wsrep_mysqld_inl.h */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user