MariaDBMon: Move replication manipulation functions to a separate file
Refactoring continues. This update moves some of the replication manipulation functions to a separate file and turns them into class methods.
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
add_library(mariadbmon SHARED mariadbmon.cc utilities.cc)
|
add_library(mariadbmon SHARED mariadbmon.cc utilities.cc cluster_manipulation.cc)
|
||||||
target_link_libraries(mariadbmon maxscale-common)
|
target_link_libraries(mariadbmon maxscale-common)
|
||||||
add_dependencies(mariadbmon pcre2)
|
add_dependencies(mariadbmon pcre2)
|
||||||
set_target_properties(mariadbmon PROPERTIES VERSION "1.4.0")
|
set_target_properties(mariadbmon PROPERTIES VERSION "1.4.0")
|
||||||
|
191
server/modules/monitor/mariadbmon/cluster_manipulation.cc
Normal file
191
server/modules/monitor/mariadbmon/cluster_manipulation.cc
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "mariadbmon.hh"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <maxscale/mysql_utils.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2020-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a CHANGE MASTER TO-query.
|
||||||
|
*
|
||||||
|
* @param master_host Master hostname/address
|
||||||
|
* @param master_port Master port
|
||||||
|
* @return Generated query
|
||||||
|
*/
|
||||||
|
string MariaDBMonitor::generate_change_master_cmd(const string& master_host, int master_port)
|
||||||
|
{
|
||||||
|
std::stringstream change_cmd;
|
||||||
|
change_cmd << "CHANGE MASTER TO MASTER_HOST = '" << master_host << "', ";
|
||||||
|
change_cmd << "MASTER_PORT = " << master_port << ", ";
|
||||||
|
change_cmd << "MASTER_USE_GTID = current_pos, ";
|
||||||
|
change_cmd << "MASTER_USER = '" << m_replication_user << "', ";
|
||||||
|
const char MASTER_PW[] = "MASTER_PASSWORD = '";
|
||||||
|
const char END[] = "';";
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
std::stringstream change_cmd_nopw;
|
||||||
|
change_cmd_nopw << change_cmd.str();
|
||||||
|
change_cmd_nopw << MASTER_PW << "******" << END;;
|
||||||
|
MXS_DEBUG("Change master command is '%s'.", change_cmd_nopw.str().c_str());
|
||||||
|
#endif
|
||||||
|
change_cmd << MASTER_PW << m_replication_password << END;
|
||||||
|
return change_cmd.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects slaves to replicate from another master server.
|
||||||
|
*
|
||||||
|
* @param slaves An array of slaves
|
||||||
|
* @param new_master The replication master
|
||||||
|
* @param redirected_slaves A vector where to insert successfully redirected slaves.
|
||||||
|
* @return The number of slaves successfully redirected.
|
||||||
|
*/
|
||||||
|
int MariaDBMonitor::redirect_slaves(MXS_MONITORED_SERVER* new_master, const ServerVector& slaves,
|
||||||
|
ServerVector* redirected_slaves)
|
||||||
|
{
|
||||||
|
ss_dassert(redirected_slaves != NULL);
|
||||||
|
MXS_NOTICE("Redirecting slaves to new master.");
|
||||||
|
string change_cmd = generate_change_master_cmd(new_master->server->name, new_master->server->port);
|
||||||
|
int successes = 0;
|
||||||
|
for (ServerVector::const_iterator iter = slaves.begin(); iter != slaves.end(); iter++)
|
||||||
|
{
|
||||||
|
if (redirect_one_slave(*iter, change_cmd.c_str()))
|
||||||
|
{
|
||||||
|
successes++;
|
||||||
|
redirected_slaves->push_back(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the new master to replicate from the cluster external master.
|
||||||
|
*
|
||||||
|
* @param new_master The server being promoted
|
||||||
|
* @param err_out Error output
|
||||||
|
* @return True if new master accepted commands
|
||||||
|
*/
|
||||||
|
bool MariaDBMonitor::start_external_replication(MXS_MONITORED_SERVER* new_master, json_t** err_out)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
string change_cmd = generate_change_master_cmd(external_master_host, external_master_port);
|
||||||
|
if (mxs_mysql_query(new_master->con, change_cmd.c_str()) == 0 &&
|
||||||
|
mxs_mysql_query(new_master->con, "START SLAVE;") == 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("New master starting replication from external master %s:%d.",
|
||||||
|
external_master_host.c_str(), external_master_port);
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_MXS_JSON_ERROR(err_out, "Could not start replication from external master: '%s'.",
|
||||||
|
mysql_error(new_master->con));
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new slave connection on a server. Should be used on a demoted master server.
|
||||||
|
*
|
||||||
|
* @param old_master The server which will start replication
|
||||||
|
* @param new_master Replication target
|
||||||
|
* @return True if commands were accepted. This does not guarantee that replication proceeds
|
||||||
|
* successfully.
|
||||||
|
*/
|
||||||
|
bool MariaDBMonitor::switchover_start_slave(MXS_MONITORED_SERVER* old_master, SERVER* new_master)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
string change_cmd = generate_change_master_cmd(new_master->name, new_master->port);
|
||||||
|
if (mxs_mysql_query(old_master->con, change_cmd.c_str()) == 0 &&
|
||||||
|
mxs_mysql_query(old_master->con, "START SLAVE;") == 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("Old master '%s' starting replication from '%s'.",
|
||||||
|
old_master->server->unique_name, new_master->unique_name);
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Old master '%s' could not start replication: '%s'.",
|
||||||
|
old_master->server->unique_name, mysql_error(old_master->con));
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect one slave server to another master
|
||||||
|
*
|
||||||
|
* @param slave Server to redirect
|
||||||
|
* @param change_cmd Change master command, usually generated by generate_change_master_cmd()
|
||||||
|
* @return True if slave accepted all commands
|
||||||
|
*/
|
||||||
|
bool MariaDBMonitor::redirect_one_slave(MXS_MONITORED_SERVER* slave, const char* change_cmd)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
if (mxs_mysql_query(slave->con, "STOP SLAVE;") == 0 &&
|
||||||
|
mxs_mysql_query(slave->con, "RESET SLAVE;") == 0 && // To erase any old I/O or SQL errors
|
||||||
|
mxs_mysql_query(slave->con, change_cmd) == 0 &&
|
||||||
|
mxs_mysql_query(slave->con, "START SLAVE;") == 0)
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
MXS_NOTICE("Slave '%s' redirected to new master.", slave->server->unique_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_WARNING("Slave '%s' redirection failed: '%s'.", slave->server->unique_name,
|
||||||
|
mysql_error(slave->con));
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t MariaDBMonitor::do_rejoin(const ServerVector& joinable_servers)
|
||||||
|
{
|
||||||
|
SERVER* master = this->master->server;
|
||||||
|
uint32_t servers_joined = 0;
|
||||||
|
if (!joinable_servers.empty())
|
||||||
|
{
|
||||||
|
string change_cmd = generate_change_master_cmd(master->name, master->port);
|
||||||
|
for (ServerVector::const_iterator iter = joinable_servers.begin();
|
||||||
|
iter != joinable_servers.end();
|
||||||
|
iter++)
|
||||||
|
{
|
||||||
|
MXS_MONITORED_SERVER* joinable = *iter;
|
||||||
|
const char* name = joinable->server->unique_name;
|
||||||
|
const char* master_name = master->unique_name;
|
||||||
|
MySqlServerInfo* redir_info = get_server_info(this, joinable);
|
||||||
|
|
||||||
|
bool op_success;
|
||||||
|
if (redir_info->n_slaves_configured == 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("Directing standalone server '%s' to replicate from '%s'.", name, master_name);
|
||||||
|
op_success = join_cluster(joinable, change_cmd.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_NOTICE("Server '%s' is replicating from a server other than '%s', "
|
||||||
|
"redirecting it to '%s'.", name, master_name, master_name);
|
||||||
|
op_success = redirect_one_slave(joinable, change_cmd.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op_success)
|
||||||
|
{
|
||||||
|
servers_joined++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers_joined;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MariaDBMonitor::cluster_can_be_joined()
|
||||||
|
{
|
||||||
|
return (master != NULL && SERVER_IS_MASTER(master->server) && master_gtid_domain >= 0);
|
||||||
|
}
|
@ -20,14 +20,11 @@
|
|||||||
#include "mariadbmon.hh"
|
#include "mariadbmon.hh"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
|
||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
#include <maxscale/dcb.h>
|
#include <maxscale/dcb.h>
|
||||||
#include <maxscale/debug.h>
|
#include <maxscale/debug.h>
|
||||||
#include <maxscale/hk_heartbeat.h>
|
#include <maxscale/hk_heartbeat.h>
|
||||||
#include <maxscale/json_api.h>
|
|
||||||
#include <maxscale/modulecmd.h>
|
#include <maxscale/modulecmd.h>
|
||||||
#include <maxscale/modutil.h>
|
#include <maxscale/modutil.h>
|
||||||
#include <maxscale/mysql_utils.h>
|
#include <maxscale/mysql_utils.h>
|
||||||
@ -59,16 +56,6 @@
|
|||||||
#define SLAVE_HOSTS_HOSTNAME 1
|
#define SLAVE_HOSTS_HOSTNAME 1
|
||||||
#define SLAVE_HOSTS_PORT 2
|
#define SLAVE_HOSTS_PORT 2
|
||||||
|
|
||||||
/** Utility macro for printing both MXS_ERROR and json error */
|
|
||||||
#define PRINT_MXS_JSON_ERROR(err_out, format, ...)\
|
|
||||||
do {\
|
|
||||||
MXS_ERROR(format, ##__VA_ARGS__);\
|
|
||||||
if (err_out)\
|
|
||||||
{\
|
|
||||||
*err_out = mxs_json_error_append(*err_out, format, ##__VA_ARGS__);\
|
|
||||||
}\
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
typedef std::vector<string> StringVector;
|
typedef std::vector<string> StringVector;
|
||||||
class MySqlServerInfo;
|
class MySqlServerInfo;
|
||||||
@ -100,8 +87,6 @@ static void set_slave_heartbeat(MXS_MONITOR *, MXS_MONITORED_SERVER *);
|
|||||||
static int add_slave_to_master(long *, int, long);
|
static int add_slave_to_master(long *, int, long);
|
||||||
static bool isMySQLEvent(mxs_monitor_event_t event);
|
static bool isMySQLEvent(mxs_monitor_event_t event);
|
||||||
void check_maxscale_schema_replication(MXS_MONITOR *monitor);
|
void check_maxscale_schema_replication(MXS_MONITOR *monitor);
|
||||||
static MySqlServerInfo* get_server_info(MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db);
|
|
||||||
static const MySqlServerInfo* get_server_info(const MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db);
|
|
||||||
static bool mon_process_failover(MariaDBMonitor*, uint32_t, bool*);
|
static bool mon_process_failover(MariaDBMonitor*, uint32_t, bool*);
|
||||||
static bool do_failover(MariaDBMonitor* mon, json_t** output);
|
static bool do_failover(MariaDBMonitor* mon, json_t** output);
|
||||||
static bool do_switchover(MariaDBMonitor* mon, MXS_MONITORED_SERVER* current_master,
|
static bool do_switchover(MariaDBMonitor* mon, MXS_MONITORED_SERVER* current_master,
|
||||||
@ -114,10 +99,8 @@ static void read_server_variables(MXS_MONITORED_SERVER* database, MySqlServerInf
|
|||||||
static bool server_is_rejoin_suspect(MariaDBMonitor* mon, MXS_MONITORED_SERVER* server,
|
static bool server_is_rejoin_suspect(MariaDBMonitor* mon, MXS_MONITORED_SERVER* server,
|
||||||
MySqlServerInfo* master_info);
|
MySqlServerInfo* master_info);
|
||||||
static bool get_joinable_servers(MariaDBMonitor* mon, ServerVector* output);
|
static bool get_joinable_servers(MariaDBMonitor* mon, ServerVector* output);
|
||||||
static uint32_t do_rejoin(MariaDBMonitor* mon, const ServerVector& servers);
|
|
||||||
static bool join_cluster(MXS_MONITORED_SERVER* server, const char* change_cmd);
|
static bool join_cluster(MXS_MONITORED_SERVER* server, const char* change_cmd);
|
||||||
static void disable_setting(MariaDBMonitor* mon, const char* setting);
|
static void disable_setting(MariaDBMonitor* mon, const char* setting);
|
||||||
static bool cluster_can_be_joined(MariaDBMonitor* mon);
|
|
||||||
static bool can_replicate_from(MariaDBMonitor* mon,
|
static bool can_replicate_from(MariaDBMonitor* mon,
|
||||||
MXS_MONITORED_SERVER* slave, MySqlServerInfo* slave_info,
|
MXS_MONITORED_SERVER* slave, MySqlServerInfo* slave_info,
|
||||||
MXS_MONITORED_SERVER* master, MySqlServerInfo* master_info);
|
MXS_MONITORED_SERVER* master, MySqlServerInfo* master_info);
|
||||||
@ -125,7 +108,6 @@ static bool wait_cluster_stabilization(MariaDBMonitor* mon, MXS_MONITORED_SERVER
|
|||||||
const ServerVector& slaves, int seconds_remaining);
|
const ServerVector& slaves, int seconds_remaining);
|
||||||
static string get_connection_errors(const ServerVector& servers);
|
static string get_connection_errors(const ServerVector& servers);
|
||||||
static int64_t scan_server_id(const char* id_string);
|
static int64_t scan_server_id(const char* id_string);
|
||||||
static string generate_change_master_cmd(MariaDBMonitor* mon, const string& master_host, int master_port);
|
|
||||||
|
|
||||||
static bool report_version_err = true;
|
static bool report_version_err = true;
|
||||||
static const char* hb_table_name = "maxscale_schema.replication_heartbeat";
|
static const char* hb_table_name = "maxscale_schema.replication_heartbeat";
|
||||||
@ -549,7 +531,7 @@ bool mysql_rejoin(MXS_MONITOR* mon, SERVER* rejoin_server, json_t** output)
|
|||||||
|
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
MariaDBMonitor *handle = static_cast<MariaDBMonitor*>(mon->handle);
|
MariaDBMonitor *handle = static_cast<MariaDBMonitor*>(mon->handle);
|
||||||
if (cluster_can_be_joined(handle))
|
if (handle->cluster_can_be_joined())
|
||||||
{
|
{
|
||||||
MXS_MONITORED_SERVER* mon_server = mon_get_monitored_server(mon, rejoin_server);
|
MXS_MONITORED_SERVER* mon_server = mon_get_monitored_server(mon, rejoin_server);
|
||||||
if (mon_server)
|
if (mon_server)
|
||||||
@ -564,7 +546,7 @@ bool mysql_rejoin(MXS_MONITOR* mon, SERVER* rejoin_server, json_t** output)
|
|||||||
{
|
{
|
||||||
ServerVector joinable_server;
|
ServerVector joinable_server;
|
||||||
joinable_server.push_back(mon_server);
|
joinable_server.push_back(mon_server);
|
||||||
if (do_rejoin(handle, joinable_server) == 1)
|
if (handle->do_rejoin(joinable_server) == 1)
|
||||||
{
|
{
|
||||||
rval = true;
|
rval = true;
|
||||||
MXS_NOTICE("Rejoin performed.");
|
MXS_NOTICE("Rejoin performed.");
|
||||||
@ -785,36 +767,36 @@ void init_server_info(MariaDBMonitor *handle)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MySqlServerInfo* get_server_info(MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db)
|
MySqlServerInfo* get_server_info(MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db)
|
||||||
{
|
{
|
||||||
ServerInfoMap::iterator iter = handle->server_info.find(db);
|
ServerInfoMap::iterator iter = handle->server_info.find(db);
|
||||||
ss_dassert(iter != handle->server_info.end());
|
ss_dassert(iter != handle->server_info.end());
|
||||||
return &iter->second;
|
return &iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MySqlServerInfo* get_server_info(const MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db)
|
const MySqlServerInfo* get_server_info(const MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db)
|
||||||
{
|
{
|
||||||
return get_server_info(const_cast<MariaDBMonitor*>(handle), db);
|
return get_server_info(const_cast<MariaDBMonitor*>(handle), db);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_replication_credentials(MariaDBMonitor *handle, const MXS_CONFIG_PARAMETER* params)
|
bool MariaDBMonitor::set_replication_credentials(const MXS_CONFIG_PARAMETER* params)
|
||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
const char* repl_user = config_get_string(params, CN_REPLICATION_USER);
|
string repl_user = config_get_string(params, CN_REPLICATION_USER);
|
||||||
const char* repl_pw = config_get_string(params, CN_REPLICATION_PASSWORD);
|
string repl_pw = config_get_string(params, CN_REPLICATION_PASSWORD);
|
||||||
|
|
||||||
if (!*repl_user && !*repl_pw)
|
if (repl_user.empty() && repl_pw.empty())
|
||||||
{
|
{
|
||||||
// No replication credentials defined, use monitor credentials
|
// No replication credentials defined, use monitor credentials
|
||||||
repl_user = handle->monitor->user;
|
repl_user = monitor->user;
|
||||||
repl_pw = handle->monitor->password;
|
repl_pw = monitor->password;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*repl_user && *repl_pw)
|
if (!repl_user.empty() && !repl_pw.empty())
|
||||||
{
|
{
|
||||||
handle->replication_user = repl_user;
|
m_replication_user = repl_user;
|
||||||
char* decrypted = decrypt_password(repl_pw);
|
char* decrypted = decrypt_password(repl_pw.c_str());
|
||||||
handle->replication_password = decrypted;
|
m_replication_password = decrypted;
|
||||||
MXS_FREE(decrypted);
|
MXS_FREE(decrypted);
|
||||||
rval = true;
|
rval = true;
|
||||||
}
|
}
|
||||||
@ -860,8 +842,6 @@ startMonitor(MXS_MONITOR *monitor, const MXS_CONFIG_PARAMETER* params)
|
|||||||
{
|
{
|
||||||
handle->shutdown = 0;
|
handle->shutdown = 0;
|
||||||
handle->script.clear();
|
handle->script.clear();
|
||||||
handle->replication_user.clear();
|
|
||||||
handle->replication_password.clear();
|
|
||||||
handle->excluded_servers.clear();
|
handle->excluded_servers.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -904,7 +884,7 @@ startMonitor(MXS_MONITOR *monitor, const MXS_CONFIG_PARAMETER* params)
|
|||||||
}
|
}
|
||||||
MXS_FREE(excluded_array);
|
MXS_FREE(excluded_array);
|
||||||
|
|
||||||
if (!set_replication_credentials(handle, params))
|
if (!handle->set_replication_credentials(params))
|
||||||
{
|
{
|
||||||
MXS_ERROR("Both '%s' and '%s' must be defined", CN_REPLICATION_USER, CN_REPLICATION_PASSWORD);
|
MXS_ERROR("Both '%s' and '%s' must be defined", CN_REPLICATION_USER, CN_REPLICATION_PASSWORD);
|
||||||
error = true;
|
error = true;
|
||||||
@ -2364,13 +2344,13 @@ monitorMain(void *arg)
|
|||||||
// Do not auto-join servers on this monitor loop if a failover (or any other cluster modification)
|
// Do not auto-join servers on this monitor loop if a failover (or any other cluster modification)
|
||||||
// has been performed, as server states have not been updated yet. It will happen next iteration.
|
// has been performed, as server states have not been updated yet. It will happen next iteration.
|
||||||
if (!config_get_global_options()->passive && handle->auto_rejoin &&
|
if (!config_get_global_options()->passive && handle->auto_rejoin &&
|
||||||
!failover_performed && cluster_can_be_joined(handle))
|
!failover_performed && handle->cluster_can_be_joined())
|
||||||
{
|
{
|
||||||
// Check if any servers should be autojoined to the cluster
|
// Check if any servers should be autojoined to the cluster
|
||||||
ServerVector joinable_servers;
|
ServerVector joinable_servers;
|
||||||
if (get_joinable_servers(handle, &joinable_servers))
|
if (get_joinable_servers(handle, &joinable_servers))
|
||||||
{
|
{
|
||||||
uint32_t joins = do_rejoin(handle, joinable_servers);
|
uint32_t joins = handle->do_rejoin(joinable_servers);
|
||||||
if (joins > 0)
|
if (joins > 0)
|
||||||
{
|
{
|
||||||
MXS_NOTICE("%d server(s) redirected or rejoined the cluster.", joins);
|
MXS_NOTICE("%d server(s) redirected or rejoined the cluster.", joins);
|
||||||
@ -3461,25 +3441,6 @@ bool failover_wait_relay_log(MariaDBMonitor* mon, MXS_MONITORED_SERVER* new_mast
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool start_external_replication(MariaDBMonitor* mon, MXS_MONITORED_SERVER* new_master, json_t** err_out)
|
|
||||||
{
|
|
||||||
bool rval = false;
|
|
||||||
string change_cmd = generate_change_master_cmd(mon, mon->external_master_host, mon->external_master_port);
|
|
||||||
if (mxs_mysql_query(new_master->con, change_cmd.c_str()) == 0 &&
|
|
||||||
mxs_mysql_query(new_master->con, "START SLAVE;") == 0)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("New master starting replication from external master %s:%d.",
|
|
||||||
mon->external_master_host.c_str(), mon->external_master_port);
|
|
||||||
rval = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PRINT_MXS_JSON_ERROR(err_out, "Could not start replication from external master: '%s'.",
|
|
||||||
mysql_error(new_master->con));
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares a server for the replication master role.
|
* Prepares a server for the replication master role.
|
||||||
*
|
*
|
||||||
@ -3514,96 +3475,13 @@ bool promote_new_master(MariaDBMonitor* mon, MXS_MONITORED_SERVER* new_master, j
|
|||||||
// If the previous master was a slave to an external master, start the equivalent slave connection on
|
// If the previous master was a slave to an external master, start the equivalent slave connection on
|
||||||
// the new master. Success of replication is not checked.
|
// the new master. Success of replication is not checked.
|
||||||
else if (mon->external_master_port != PORT_UNKNOWN &&
|
else if (mon->external_master_port != PORT_UNKNOWN &&
|
||||||
!start_external_replication(mon, new_master, err_out))
|
!mon->start_external_replication(new_master, err_out))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a CHANGE MASTER TO-query.
|
|
||||||
*
|
|
||||||
* @param mon Cluster monitor, needed for username & password
|
|
||||||
* @param master_host Master hostname/address
|
|
||||||
* @param master_port Master port
|
|
||||||
* @return Generated query
|
|
||||||
*/
|
|
||||||
string generate_change_master_cmd(MariaDBMonitor* mon, const string& master_host, int master_port)
|
|
||||||
{
|
|
||||||
std::stringstream change_cmd;
|
|
||||||
change_cmd << "CHANGE MASTER TO MASTER_HOST = '" << master_host << "', ";
|
|
||||||
change_cmd << "MASTER_PORT = " << master_port << ", ";
|
|
||||||
change_cmd << "MASTER_USE_GTID = current_pos, ";
|
|
||||||
change_cmd << "MASTER_USER = '" << mon->replication_user << "', ";
|
|
||||||
const char MASTER_PW[] = "MASTER_PASSWORD = '";
|
|
||||||
const char END[] = "';";
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
std::stringstream change_cmd_nopw;
|
|
||||||
change_cmd_nopw << change_cmd.str();
|
|
||||||
change_cmd_nopw << MASTER_PW << "******" << END;;
|
|
||||||
MXS_DEBUG("Change master command is '%s'.", change_cmd_nopw.str().c_str());
|
|
||||||
#endif
|
|
||||||
change_cmd << MASTER_PW << mon->replication_password << END;
|
|
||||||
return change_cmd.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect one slave server to another master
|
|
||||||
*
|
|
||||||
* @param slave Server to redirect
|
|
||||||
* @param change_cmd Change master command, usually generated by generate_change_master_cmd()
|
|
||||||
* @return True if slave accepted all commands
|
|
||||||
*/
|
|
||||||
bool redirect_one_slave(MXS_MONITORED_SERVER* slave, const char* change_cmd)
|
|
||||||
{
|
|
||||||
bool rval = false;
|
|
||||||
if (mxs_mysql_query(slave->con, "STOP SLAVE;") == 0 &&
|
|
||||||
mxs_mysql_query(slave->con, "RESET SLAVE;") == 0 && // To erase any old I/O or SQL errors
|
|
||||||
mxs_mysql_query(slave->con, change_cmd) == 0 &&
|
|
||||||
mxs_mysql_query(slave->con, "START SLAVE;") == 0)
|
|
||||||
{
|
|
||||||
rval = true;
|
|
||||||
MXS_NOTICE("Slave '%s' redirected to new master.", slave->server->unique_name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_WARNING("Slave '%s' redirection failed: '%s'.", slave->server->unique_name,
|
|
||||||
mysql_error(slave->con));
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirects slaves to replicate from another master server.
|
|
||||||
*
|
|
||||||
* @param mon The monitor
|
|
||||||
* @param slaves An array of slaves
|
|
||||||
* @param new_master The replication master
|
|
||||||
* @param redirected_slaves A vector where to insert successfully redirected slaves. Can be NULL.
|
|
||||||
* @return The number of slaves successfully redirected.
|
|
||||||
*/
|
|
||||||
int redirect_slaves(MariaDBMonitor* mon, MXS_MONITORED_SERVER* new_master, const ServerVector& slaves,
|
|
||||||
ServerVector* redirected_slaves = NULL)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("Redirecting slaves to new master.");
|
|
||||||
std::string change_cmd = generate_change_master_cmd(mon,
|
|
||||||
new_master->server->name, new_master->server->port);
|
|
||||||
int successes = 0;
|
|
||||||
for (ServerVector::const_iterator iter = slaves.begin(); iter != slaves.end(); iter++)
|
|
||||||
{
|
|
||||||
if (redirect_one_slave(*iter, change_cmd.c_str()))
|
|
||||||
{
|
|
||||||
successes++;
|
|
||||||
if (redirected_slaves)
|
|
||||||
{
|
|
||||||
redirected_slaves->push_back(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return successes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print a redirect error to logs. If err_out exists, generate a combined error message by querying all
|
* Print a redirect error to logs. If err_out exists, generate a combined error message by querying all
|
||||||
* the server parameters for connection errors and append these errors to err_out.
|
* the server parameters for connection errors and append these errors to err_out.
|
||||||
@ -3677,7 +3555,7 @@ static bool do_failover(MariaDBMonitor* mon, json_t** err_out)
|
|||||||
{
|
{
|
||||||
// Step 4: Redirect slaves.
|
// Step 4: Redirect slaves.
|
||||||
ServerVector redirected_slaves;
|
ServerVector redirected_slaves;
|
||||||
int redirects = redirect_slaves(mon, new_master, redirectable_slaves, &redirected_slaves);
|
int redirects = mon->redirect_slaves(new_master, redirectable_slaves, &redirected_slaves);
|
||||||
bool success = redirectable_slaves.empty() ? true : redirects > 0;
|
bool success = redirectable_slaves.empty() ? true : redirects > 0;
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -4020,34 +3898,6 @@ static bool switchover_wait_slaves_catchup(const ServerVector& slaves, const Gti
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new slave connection on a server. Should be used on a demoted master server.
|
|
||||||
*
|
|
||||||
* @param mon Cluster monitor
|
|
||||||
* @param old_master The server which will start replication
|
|
||||||
* @param new_master Replication target
|
|
||||||
* @return True if commands were accepted. This does not guarantee that replication proceeds
|
|
||||||
* successfully.
|
|
||||||
*/
|
|
||||||
static bool switchover_start_slave(MariaDBMonitor* mon, MXS_MONITORED_SERVER* old_master, SERVER* new_master)
|
|
||||||
{
|
|
||||||
bool rval = false;
|
|
||||||
std::string change_cmd = generate_change_master_cmd(mon, new_master->name, new_master->port);
|
|
||||||
if (mxs_mysql_query(old_master->con, change_cmd.c_str()) == 0 &&
|
|
||||||
mxs_mysql_query(old_master->con, "START SLAVE;") == 0)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("Old master '%s' starting replication from '%s'.",
|
|
||||||
old_master->server->unique_name, new_master->unique_name);
|
|
||||||
rval = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_ERROR("Old master '%s' could not start replication: '%s'.",
|
|
||||||
old_master->server->unique_name, mysql_error(old_master->con));
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get MariaDB connection error strings from all the given servers, form one string.
|
* Get MariaDB connection error strings from all the given servers, form one string.
|
||||||
*
|
*
|
||||||
@ -4256,13 +4106,13 @@ static bool do_switchover(MariaDBMonitor* mon, MXS_MONITORED_SERVER* current_mas
|
|||||||
catchup_and_promote_success = true;
|
catchup_and_promote_success = true;
|
||||||
// Step 5: Redirect slaves and start replication on old master.
|
// Step 5: Redirect slaves and start replication on old master.
|
||||||
ServerVector redirected_slaves;
|
ServerVector redirected_slaves;
|
||||||
bool start_ok = switchover_start_slave(mon, demotion_target, promotion_target->server);
|
bool start_ok = mon->switchover_start_slave(demotion_target, promotion_target->server);
|
||||||
if (start_ok)
|
if (start_ok)
|
||||||
{
|
{
|
||||||
redirected_slaves.push_back(demotion_target);
|
redirected_slaves.push_back(demotion_target);
|
||||||
}
|
}
|
||||||
int redirects = redirect_slaves(mon, promotion_target,
|
int redirects = mon->redirect_slaves(promotion_target, redirectable_slaves,
|
||||||
redirectable_slaves, &redirected_slaves);
|
&redirected_slaves);
|
||||||
|
|
||||||
bool success = redirectable_slaves.empty() ? start_ok : start_ok || redirects > 0;
|
bool success = redirectable_slaves.empty() ? start_ok : start_ok || redirects > 0;
|
||||||
if (success)
|
if (success)
|
||||||
@ -4314,7 +4164,7 @@ static bool do_switchover(MariaDBMonitor* mon, MXS_MONITORED_SERVER* current_mas
|
|||||||
// Try to reactivate external replication if any.
|
// Try to reactivate external replication if any.
|
||||||
if (mon->external_master_port != PORT_UNKNOWN)
|
if (mon->external_master_port != PORT_UNKNOWN)
|
||||||
{
|
{
|
||||||
start_external_replication(mon, new_master, err_out);
|
mon->start_external_replication(new_master, err_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4489,52 +4339,6 @@ static bool get_joinable_servers(MariaDBMonitor* mon, ServerVector* output)
|
|||||||
return comm_ok;
|
return comm_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* (Re)join given servers to the cluster. The servers in the array are assumed to be joinable.
|
|
||||||
* Usually the list is created by get_joinable_servers().
|
|
||||||
*
|
|
||||||
* @param mon Cluster monitor
|
|
||||||
* @param joinable_servers Which servers to rejoin
|
|
||||||
* @return The number of servers successfully rejoined
|
|
||||||
*/
|
|
||||||
static uint32_t do_rejoin(MariaDBMonitor* mon, const ServerVector& joinable_servers)
|
|
||||||
{
|
|
||||||
SERVER* master = mon->master->server;
|
|
||||||
uint32_t servers_joined = 0;
|
|
||||||
if (!joinable_servers.empty())
|
|
||||||
{
|
|
||||||
string change_cmd = generate_change_master_cmd(mon, master->name, master->port);
|
|
||||||
for (ServerVector::const_iterator iter = joinable_servers.begin();
|
|
||||||
iter != joinable_servers.end();
|
|
||||||
iter++)
|
|
||||||
{
|
|
||||||
MXS_MONITORED_SERVER* joinable = *iter;
|
|
||||||
const char* name = joinable->server->unique_name;
|
|
||||||
const char* master_name = master->unique_name;
|
|
||||||
MySqlServerInfo* redir_info = get_server_info(mon, joinable);
|
|
||||||
|
|
||||||
bool op_success;
|
|
||||||
if (redir_info->n_slaves_configured == 0)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("Directing standalone server '%s' to replicate from '%s'.", name, master_name);
|
|
||||||
op_success = join_cluster(joinable, change_cmd.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_NOTICE("Server '%s' is replicating from a server other than '%s', "
|
|
||||||
"redirecting it to '%s'.", name, master_name, master_name);
|
|
||||||
op_success = redirect_one_slave(joinable, change_cmd.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op_success)
|
|
||||||
{
|
|
||||||
servers_joined++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return servers_joined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Joins a standalone server to the cluster.
|
* Joins a standalone server to the cluster.
|
||||||
*
|
*
|
||||||
@ -4542,7 +4346,7 @@ static uint32_t do_rejoin(MariaDBMonitor* mon, const ServerVector& joinable_serv
|
|||||||
* @param change_cmd Change master command
|
* @param change_cmd Change master command
|
||||||
* @return True if commands were accepted by server
|
* @return True if commands were accepted by server
|
||||||
*/
|
*/
|
||||||
static bool join_cluster(MXS_MONITORED_SERVER* server, const char* change_cmd)
|
bool MariaDBMonitor::join_cluster(MXS_MONITORED_SERVER* server, const char* change_cmd)
|
||||||
{
|
{
|
||||||
/* Server does not have slave connections. This operation can fail, or the resulting
|
/* Server does not have slave connections. This operation can fail, or the resulting
|
||||||
* replication may end up broken. */
|
* replication may end up broken. */
|
||||||
@ -4575,17 +4379,6 @@ static void disable_setting(MariaDBMonitor* mon, const char* setting)
|
|||||||
monitorAddParameters(mon->monitor, &p);
|
monitorAddParameters(mon->monitor, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the cluster a valid rejoin target
|
|
||||||
*
|
|
||||||
* @param mon Cluster monitor
|
|
||||||
* @return True, if cluster can be joined
|
|
||||||
*/
|
|
||||||
static bool cluster_can_be_joined(MariaDBMonitor* mon)
|
|
||||||
{
|
|
||||||
return (mon->master != NULL && SERVER_IS_MASTER(mon->master->server) && mon->master_gtid_domain >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan a server id from a string.
|
* Scan a server id from a string.
|
||||||
*
|
*
|
||||||
|
@ -22,17 +22,32 @@
|
|||||||
#include <tr1/unordered_map>
|
#include <tr1/unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <maxscale/json_api.h>
|
||||||
#include <maxscale/monitor.h>
|
#include <maxscale/monitor.h>
|
||||||
#include <maxscale/thread.h>
|
#include <maxscale/thread.h>
|
||||||
|
|
||||||
#include "utilities.hh"
|
#include "utilities.hh"
|
||||||
|
|
||||||
|
/** Utility macro for printing both MXS_ERROR and json error */
|
||||||
|
#define PRINT_MXS_JSON_ERROR(err_out, format, ...)\
|
||||||
|
do {\
|
||||||
|
MXS_ERROR(format, ##__VA_ARGS__);\
|
||||||
|
if (err_out)\
|
||||||
|
{\
|
||||||
|
*err_out = mxs_json_error_append(*err_out, format, ##__VA_ARGS__);\
|
||||||
|
}\
|
||||||
|
} while (false)
|
||||||
|
|
||||||
extern const int PORT_UNKNOWN;
|
extern const int PORT_UNKNOWN;
|
||||||
extern const int64_t SERVER_ID_UNKNOWN;
|
extern const int64_t SERVER_ID_UNKNOWN;
|
||||||
|
class MariaDBMonitor;
|
||||||
|
|
||||||
typedef std::tr1::unordered_map<const MXS_MONITORED_SERVER*, MySqlServerInfo> ServerInfoMap;
|
typedef std::tr1::unordered_map<const MXS_MONITORED_SERVER*, MySqlServerInfo> ServerInfoMap;
|
||||||
typedef std::vector<MXS_MONITORED_SERVER*> ServerVector;
|
typedef std::vector<MXS_MONITORED_SERVER*> ServerVector;
|
||||||
|
|
||||||
|
MySqlServerInfo* get_server_info(MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db);
|
||||||
|
const MySqlServerInfo* get_server_info(const MariaDBMonitor* handle, const MXS_MONITORED_SERVER* db);
|
||||||
|
|
||||||
// MySQL Monitor module instance
|
// MySQL Monitor module instance
|
||||||
class MariaDBMonitor
|
class MariaDBMonitor
|
||||||
{
|
{
|
||||||
@ -43,6 +58,22 @@ public:
|
|||||||
MariaDBMonitor();
|
MariaDBMonitor();
|
||||||
~MariaDBMonitor();
|
~MariaDBMonitor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)join given servers to the cluster. The servers in the array are assumed to be joinable.
|
||||||
|
* Usually the list is created by get_joinable_servers().
|
||||||
|
*
|
||||||
|
* @param joinable_servers Which servers to rejoin
|
||||||
|
* @return The number of servers successfully rejoined
|
||||||
|
*/
|
||||||
|
uint32_t do_rejoin(const ServerVector& joinable_servers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cluster is a valid rejoin target.
|
||||||
|
*
|
||||||
|
* @return True if master and gtid domain are known
|
||||||
|
*/
|
||||||
|
bool cluster_can_be_joined();
|
||||||
|
|
||||||
MXS_MONITOR* monitor; /**< Generic monitor object */
|
MXS_MONITOR* monitor; /**< Generic monitor object */
|
||||||
THREAD thread; /**< Monitor thread */
|
THREAD thread; /**< Monitor thread */
|
||||||
int shutdown; /**< Flag to shutdown the monitor thread */
|
int shutdown; /**< Flag to shutdown the monitor thread */
|
||||||
@ -67,8 +98,6 @@ public:
|
|||||||
bool replicationHeartbeat; /**< Monitor flag for MySQL replication heartbeat */
|
bool replicationHeartbeat; /**< Monitor flag for MySQL replication heartbeat */
|
||||||
|
|
||||||
// Failover, switchover and rejoin settings
|
// Failover, switchover and rejoin settings
|
||||||
string replication_user; /**< Replication user for CHANGE MASTER TO-commands */
|
|
||||||
string replication_password; /**< Replication password for CHANGE MASTER TO-commands */
|
|
||||||
int failcount; /**< How many monitoring cycles master must be down before auto-failover
|
int failcount; /**< How many monitoring cycles master must be down before auto-failover
|
||||||
* begins */
|
* begins */
|
||||||
uint32_t failover_timeout; /**< Timeout in seconds for the master failover */
|
uint32_t failover_timeout; /**< Timeout in seconds for the master failover */
|
||||||
@ -84,4 +113,20 @@ public:
|
|||||||
string script; /**< Script to call when state changes occur on servers */
|
string script; /**< Script to call when state changes occur on servers */
|
||||||
uint64_t events; /**< enabled events */
|
uint64_t events; /**< enabled events */
|
||||||
bool allow_cluster_recovery; /**< Allow failed servers to rejoin the cluster */
|
bool allow_cluster_recovery; /**< Allow failed servers to rejoin the cluster */
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Failover, switchover and rejoin settings
|
||||||
|
string m_replication_user; /**< Replication user for CHANGE MASTER TO-commands */
|
||||||
|
string m_replication_password; /**< Replication password for CHANGE MASTER TO-commands */
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Following methods should be private, change it once refactoring is done.
|
||||||
|
string generate_change_master_cmd(const string& master_host, int master_port);
|
||||||
|
int redirect_slaves(MXS_MONITORED_SERVER* new_master, const ServerVector& slaves,
|
||||||
|
ServerVector* redirected_slaves);
|
||||||
|
bool set_replication_credentials(const MXS_CONFIG_PARAMETER* params);
|
||||||
|
bool start_external_replication(MXS_MONITORED_SERVER* new_master, json_t** err_out);
|
||||||
|
bool switchover_start_slave(MXS_MONITORED_SERVER* old_master, SERVER* new_master);
|
||||||
|
bool redirect_one_slave(MXS_MONITORED_SERVER* slave, const char* change_cmd);
|
||||||
|
bool join_cluster(MXS_MONITORED_SERVER* server, const char* change_cmd);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user