MXS-2011 Allow alternative connections to be specified

Alternative masters can now be specified like

  CHANGE MASTER TO ...
  CHANGE MASTER ":2" TO ...
  CHANGE MASTER ":3" TO ...

Now only the data is stored, but it is neither used nor
saved.
This commit is contained in:
Johan Wikman 2018-08-28 12:05:12 +03:00
parent 93dc75a011
commit 0c3fcfe302
3 changed files with 133 additions and 14 deletions

View File

@ -29,6 +29,7 @@
#include <string>
#include <thread>
#include <vector>
#include <maxscale/buffer.h>
#include <maxscale/dcb.h>
@ -367,6 +368,7 @@ public:
class ChangeMasterConfig
{
public:
std::string connection_name;
std::string host;
int port;
std::string binlog_file;
@ -392,6 +394,16 @@ struct ROUTER_INSTANCE;
class ChangeMasterOptions
{
public:
ChangeMasterOptions()
{
}
ChangeMasterOptions(const std::string& s)
: connection_name(s)
{
}
std::string connection_name;
std::string host;
std::string port;
std::string binlog_file;
@ -788,7 +800,7 @@ struct ROUTER_INSTANCE: public MXS_ROUTER
enum binlog_storage_type storage_type;/*< Enables hierachical binlog file storage */
char *set_slave_hostname; /*< Send custom Hostname to Master */
ROUTER_INSTANCE *next;
ChangeMasterConfig config; /*< Current config. */
std::vector<ChangeMasterConfig> configs; /*< Current config. */
};
/** Master Semi-Sync capability */

View File

@ -136,7 +136,6 @@ static void blr_log_header(int priority, const char *msg, uint8_t *ptr);
void blr_cache_read_master_data(ROUTER_INSTANCE *router);
int blr_file_get_next_binlogname(ROUTER_INSTANCE *router);
int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file);
int blr_file_write_master_config(ROUTER_INSTANCE *router, char *error);
extern uint32_t extract_field(uint8_t *src, int bits);
static void blr_format_event_size(double *event_size, char *label);
extern int MaxScaleUptime();

View File

@ -49,6 +49,9 @@
#include <maxscale/utils.h>
#include <maxscale/version.h>
using std::string;
using std::vector;
/**
* This struct is used by sqlite3_exec callback routine
* for SHOW BINARY LOGS.
@ -4210,6 +4213,7 @@ bool ChangeMasterOptions::validate(ROUTER_INSTANCE* router,
}
}
config->connection_name = this->connection_name;
config->host = this->host;
config->port = port;
config->binlog_file = this->binlog_file;
@ -4228,13 +4232,78 @@ bool ChangeMasterOptions::validate(ROUTER_INSTANCE* router,
return true;
}
static int blr_apply_change_master(ROUTER_INSTANCE* router,
const ChangeMasterConfig& new_config,
char* error)
namespace
{
MasterServerConfig current_master;
spinlock_acquire(&router->lock);
bool validate_connection_name(ROUTER_INSTANCE* router, const std::string& name, char* error)
{
static const char DEFAULT_MESSAGE[] =
"If a connection name is provided, it must be of the format ':N' where N "
"is an integer larger than 1.";
char custom_message[BINLOG_ERROR_MSG_LEN + 1];
const char* message = DEFAULT_MESSAGE;
if (name.length() >= 2) // At minimum ":N".
{
if (name.front() == ':')
{
string tail = name.substr(1);
int n = strtol(tail.c_str(), NULL, 10);
if ((n > 1) && (std::to_string(n) == tail)) // Nothing funky in the string
{
if (router->configs.size() == static_cast<size_t>(n - 1))
{
message = nullptr;
}
else if (router->configs.size() == 0)
{
snprintf(custom_message,
BINLOG_ERROR_MSG_LEN,
"The provided connection name '%s' is not valid. Currently "
"no primary connection exists and it must be specified using "
"a 'CHANGE MASTER TO ...' command without a connection name.",
name.c_str());
message = custom_message;
}
else
{
snprintf(custom_message,
BINLOG_ERROR_MSG_LEN,
"The provided connection name '%s' is not valid. Currently "
"the primary connection and %d alternative connections have "
"been specified and the next valid name for an alternative "
"connection is ':%d'.",
name.c_str(),
(int)router->configs.size() - 1,
(int)router->configs.size() + 1);
message = custom_message;
}
}
}
}
if (message)
{
snprintf(error, BINLOG_ERROR_MSG_LEN, "%s", message);
}
return message == nullptr;
}
}
namespace
{
int blr_apply_change_master_0(ROUTER_INSTANCE* router,
const ChangeMasterConfig& new_config,
char* error)
{
mxb_assert(new_config.connection_name.empty());
MasterServerConfig current_master;
/* save current config option data */
blr_master_get_config(router, &current_master);
@ -4291,8 +4360,6 @@ static int blr_apply_change_master(ROUTER_INSTANCE* router,
current_master,
error);
spinlock_release(&router->lock);
return -1;
}
@ -4321,8 +4388,6 @@ static int blr_apply_change_master(ROUTER_INSTANCE* router,
error);
MXS_FREE(master_logfile);
spinlock_release(&router->lock);
return -1;
}
@ -4337,9 +4402,50 @@ static int blr_apply_change_master(ROUTER_INSTANCE* router,
change_binlog = 1;
}
return change_binlog;
}
int blr_apply_change_master_N(ROUTER_INSTANCE* router,
const ChangeMasterConfig& new_config,
char* error)
{
int rc = -1;
if (validate_connection_name(router, new_config.connection_name, error))
{
router->configs.push_back(new_config);
rc = 0;
}
return rc;
}
}
static int blr_apply_change_master(ROUTER_INSTANCE* router,
const ChangeMasterConfig& new_config,
char* error)
{
int rc = 0;
spinlock_acquire(&router->lock);
if (new_config.connection_name.empty())
{
// An empty connection name means we reset the whole thing.
router->configs.clear();
router->configs.push_back(new_config);
rc = blr_apply_change_master_0(router, new_config, error);
}
else
{
rc = blr_apply_change_master_N(router, new_config, error);
}
spinlock_release(&router->lock);
return change_binlog;
return rc;
}
/**
@ -4429,7 +4535,7 @@ int blr_handle_change_master(ROUTER_INSTANCE* router,
std::vector<char> cmd_string(command, command + strlen(command) + 1); // Include the NULL
/* Parse SQL command and populate the change_master struct */
ChangeMasterOptions new_options;
ChangeMasterOptions new_options(connection_name);
if (blr_parse_change_master_command(&cmd_string.front(),
error,
&new_options) != 0)
@ -8038,8 +8144,11 @@ static bool blr_handle_admin_stmt(ROUTER_INSTANCE *router,
{
int rc;
char error_string[BINLOG_ERROR_MSG_LEN + 1 + BINLOG_ERROR_MSG_LEN + 1] = "";
// TODO: Why is this without a lock, but blr_master_apply_config() below with
// TODO: a lock. One of them must be wrong.
MasterServerConfig current_master;
blr_master_get_config(router, &current_master);
vector<ChangeMasterConfig> configs = router->configs;
ChangeMasterConfig new_config;
rc = blr_handle_change_master(router, brkb, error_string, &new_config);
@ -8088,7 +8197,6 @@ static bool blr_handle_admin_stmt(ROUTER_INSTANCE *router,
/* Mark as active the master server struct */
spinlock_acquire(&router->lock);
router->config = new_config;
if (!router->service->dbref->server->is_active)
{
router->service->dbref->server->is_active = true;