Commit 13af416a authored by Sergei Golubchik's avatar Sergei Golubchik

cleanup: wsrep_check_opts

parent 425dc6d2
......@@ -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)
{
......
/* 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
{
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 (argv_)
{
for (int i = 0; i < argc_; ++i)
{
argv_[i] = strdup(argv[i]);
if (!argv_[i])
{
argv_free (); // free whatever bee allocated
return;
}
}
}
}
~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)
int wsrep_check_opts()
{
if (a.argv_)
if (wsrep_slave_threads > 1)
{
for (int i = 0; i < a.argc_; ++i)
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)
{
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"
WSREP_ERROR("Parallel applying (wsrep_slave_threads > 1) requires"
" innodb_autoinc_lock_mode = 2.");
rcode = EINVAL;
}
return 1;
}
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"))
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 "
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;
my_bind_addr_str);
return 1;
}
}
else
{
// non-mysqldump SST requires wsrep_cluster_address on startup
if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0)
if (!wsrep_cluster_address || !wsrep_cluster_address[0])
{
WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be "
"configured on startup.",opts[WSREP_SST_METHOD].value);
rcode = EINVAL;
"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")))
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 "
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;
wsrep_sst_receive_address);
}
}
if (strcasecmp(opts[WSREP_PROVIDER].value, "none"))
if (strcasecmp(wsrep_provider, "NONE"))
{
if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW"))
if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW)
{
WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. "
WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. "
"Configured value: '%s'. Please adjust your "
"configuration.", opts[BINLOG_FORMAT].value);
"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 */
......
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