master.ini contains now master configuration

master.ini contains now master configuration
It can be created or modified by CHANGE MASTER TO
Added new BLRM_UNCONFIGURED state
This commit is contained in:
MassimilianoPinto 2015-06-30 16:10:02 +02:00
parent b526da1fd4
commit 5165c6b981
4 changed files with 985 additions and 193 deletions

View File

@ -30,6 +30,7 @@
* 05/06/15 Massimiliano Pinto Addition of m_errno, m_errmsg fields
* 08/06/15 Massimiliano Pinto Modification of MYSQL_ERROR_CODE and MYSQL_ERROR_MSG
* 23/06/15 Massimiliano Pinto Addition of MASTER_SERVER_CFG struct
* 24/06/15 Massimiliano Pinto Added BLRM_UNCONFIGURED state
*
* @endverbatim
*/
@ -75,7 +76,7 @@
#define BLR_MAX_BACKOFF 60
/* max size for error message returned to client */
#define BINLOG_ERROR_MSG_LEN 255
#define BINLOG_ERROR_MSG_LEN 385
/**
* Some useful macros for examining the MySQL Response packets
@ -95,6 +96,7 @@ typedef struct master_server_config {
uint64_t pos;
char *user;
char *password;
char *filestem;
} MASTER_SERVER_CFG;
/**
@ -313,31 +315,32 @@ typedef struct router_instance {
/**
* State machine for the master to MaxScale replication
*/
#define BLRM_UNCONNECTED 0x0000
#define BLRM_CONNECTING 0x0001
#define BLRM_AUTHENTICATED 0x0002
#define BLRM_TIMESTAMP 0x0003
#define BLRM_SERVERID 0x0004
#define BLRM_HBPERIOD 0x0005
#define BLRM_CHKSUM1 0x0006
#define BLRM_CHKSUM2 0x0007
#define BLRM_GTIDMODE 0x0008
#define BLRM_MUUID 0x0009
#define BLRM_SUUID 0x000A
#define BLRM_LATIN1 0x000B
#define BLRM_UTF8 0x000C
#define BLRM_SELECT1 0x000D
#define BLRM_SELECTVER 0x000E
#define BLRM_SELECTVERCOM 0x000F
#define BLRM_SELECTHOSTNAME 0x0010
#define BLRM_MAP 0x0011
#define BLRM_REGISTER 0x0012
#define BLRM_BINLOGDUMP 0x0013
#define BLRM_SLAVE_STOPPED 0x0014
#define BLRM_UNCONFIGURED 0x0000
#define BLRM_UNCONNECTED 0x0001
#define BLRM_CONNECTING 0x0002
#define BLRM_AUTHENTICATED 0x0003
#define BLRM_TIMESTAMP 0x0004
#define BLRM_SERVERID 0x0005
#define BLRM_HBPERIOD 0x0006
#define BLRM_CHKSUM1 0x0007
#define BLRM_CHKSUM2 0x0008
#define BLRM_GTIDMODE 0x0009
#define BLRM_MUUID 0x000A
#define BLRM_SUUID 0x000B
#define BLRM_LATIN1 0x000C
#define BLRM_UTF8 0x000D
#define BLRM_SELECT1 0x000E
#define BLRM_SELECTVER 0x000F
#define BLRM_SELECTVERCOM 0x0010
#define BLRM_SELECTHOSTNAME 0x0011
#define BLRM_MAP 0x0012
#define BLRM_REGISTER 0x0013
#define BLRM_BINLOGDUMP 0x0014
#define BLRM_SLAVE_STOPPED 0x0015
#define BLRM_MAXSTATE 0x0014
#define BLRM_MAXSTATE 0x0015
static char *blrm_states[] = { "Unconnected", "Connecting", "Authenticated", "Timestamp retrieval",
static char *blrm_states[] = { "Unconfigured", "Unconnected", "Connecting", "Authenticated", "Timestamp retrieval",
"Server ID retrieval", "HeartBeat Period setup", "binlog checksum config",
"binlog checksum rerieval", "GTID Mode retrieval", "Master UUID retrieval",
"Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",

View File

@ -35,6 +35,9 @@
* 02/04/2014 Mark Riddoch Initial implementation
* 17/02/2015 Massimiliano Pinto Addition of slave port and username in diagnostics
* 18/02/2015 Massimiliano Pinto Addition of dcb_close in closeSession
* 29/06/2015 Massimiliano Pinto Addition of master.ini for easy startup configuration
* If not found router goes into BLRM_UNCONFIGURED state.
* Cache dir is 'cache' under router->binlogdir.
*
* @endverbatim
*/
@ -59,6 +62,8 @@
#include <log_manager.h>
#include <mysql_client_server_protocol.h>
#include <ini.h>
#include <sys/stat.h>
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -85,7 +90,14 @@ static void errorReply(
DCB *backend_dcb,
error_action_t action,
bool *succp);
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
static int blr_handler_config(void *userdata, const char *section, const char *name, const char *value);
static int blr_handle_config_item(const char *name, const char *value, ROUTER_INSTANCE *inst);
static int blr_set_service_mysql_user(SERVICE *service);
int blr_load_dbusers(ROUTER_INSTANCE *router);
int blr_save_dbusers(ROUTER_INSTANCE *router);
extern void blr_cache_read_master_data(ROUTER_INSTANCE *router);
/** The module object definition */
@ -168,6 +180,9 @@ ROUTER_INSTANCE *inst;
char *value, *name;
int i;
unsigned char *defuuid;
char path[PATH_MAX], filename[PATH_MAX];
int master_info = 0;
int rc = 0;
if ((inst = calloc(1, sizeof(ROUTER_INSTANCE))) == NULL) {
return NULL;
@ -186,7 +201,7 @@ unsigned char *defuuid;
inst->master_chksum = true;
inst->master_uuid = NULL;
inst->master_state = BLRM_UNCONNECTED;
inst->master_state = BLRM_UNCONFIGURED;
inst->master = NULL;
inst->client = NULL;
@ -223,20 +238,17 @@ unsigned char *defuuid;
* the master from which we replicate binlog records. Therefore check
* that only one server has been defined.
*
* A later improvement will be to define multiple servers and have the
* router use the information that is supplied by the monitor to find
* which of these servers is currently the master and replicate from
* that server.
*/
if (service->dbref == NULL || service->dbref->next != NULL)
if (service->dbref && service->dbref->next != NULL)
{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : Exactly one database server may be "
"for use with the binlog router.")));
"Error : Exactly one database server may be "
"for use with the binlog router.")));
/* report as error whether a server is defined in the service */
}
/*
* Process the options.
* We have an array of attrbute values passed to us that we must
@ -380,6 +392,117 @@ unsigned char *defuuid;
inst->binlog_position = 0;
strcpy(inst->binlog_name, "");
strcpy(inst->prevbinlog, "");
/**
* If binlogdir is not found create it
* On failure don't start the instance
*/
if (access(inst->binlogdir, R_OK) == -1) {
int mkdir_rval;
mkdir_rval = mkdir(inst->binlogdir, 0700);
if (mkdir_rval == -1) {
skygw_log_write_flush(LOGFILE_ERROR,
"Error : Service %s, Failed to create binlog directory '%s': [%d] %s",
service->name,
inst->binlogdir,
errno,
strerror(errno));
free(inst);
return NULL;
}
}
/* Allocate dbusers for this router here instead of serviceStartPort() */
if (service->users == NULL) {
service->users = (void *)mysql_users_alloc();
if (service->users == NULL) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: Error allocating dbusers in createInstance",
inst->service->name)));
free(inst);
return NULL;
}
}
/* Dinamically allocate master_host server struct, not written in anyfile */
if (service->dbref == NULL) {
SERVICE *service = inst->service;
SERVER *server;
server = server_alloc("none", "MySQLBackend", (int)1234);
if (server == NULL) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: Error for server_alloc in createInstance",
inst->service->name)));
if (service->users) {
users_free(service->users);
}
free(inst);
return NULL;
}
server_set_unique_name(server, "binlog_router_master_host");
serviceAddBackend(service, server);
}
/*
* Check for master.ini file with master connection details
* If not found a CHANGE MASTER TO is required via mysqsl client.
* Use START SLAVE for replication startup.
*
* If existent master.ini will be used for
* automatic master replication start phase
*/
strncpy(path, inst->binlogdir, PATH_MAX);
snprintf(filename,PATH_MAX, "%s/master.ini", path);
rc = ini_parse(filename, blr_handler_config, inst);
LOGIF(LT, (skygw_log_write_flush(LOGFILE_TRACE,
"%s: %s/master.ini parse result is %d",
inst->service->name,
inst->binlogdir,
rc)));
/*
* retcode:
* -1 file not found, 0 parsing ok, > 0 error parsing the content
*/
if (rc != 0) {
if (rc == -1) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: master.ini file not found in %s."
" Master registration cannot be started."
" Configure with CHANGE MASTER TO ...",
inst->service->name, inst->binlogdir)));
} else {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: master.ini file with errors in %s."
" Master registration cannot be started."
" Fix errors in it or configure with CHANGE MASTER TO ...",
inst->service->name, inst->binlogdir)));
}
} else {
/**
* master.ini configuration is ok
* Master registration can start
*/
inst->master_state = BLRM_UNCONNECTED;
master_info = 1;
}
/* Set service user or load db users */
if (inst->master_state == BLRM_UNCONFIGURED) {
blr_set_service_mysql_user(inst->service);
} else {
blr_load_dbusers(inst);
}
/*
* Read any cached response messages
@ -389,20 +512,33 @@ unsigned char *defuuid;
/*
* Initialise the binlog file and position
*/
if (blr_file_init(inst) == 0)
{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"%s: Service not started due to lack of binlog directory.",
service->name)));
free(inst);
return NULL;
}
LOGIF(LT, (skygw_log_write(
if (inst->master_state == BLRM_UNCONNECTED) {
if (blr_file_init(inst) == 0)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%s: Service not started due to lack of binlog directory %s",
service->name,
inst->binlogdir)));
if (service->users) {
users_free(service->users);
}
if (service->dbref && service->dbref->server) {
server_free(service->dbref->server);
free(service->dbref);
}
free(inst);
return NULL;
}
LOGIF(LT, (skygw_log_write_flush(
LOGFILE_TRACE,
"Binlog router: current binlog file is: %s, current position %u\n",
inst->binlog_name, inst->binlog_position)));
inst->binlog_name, inst->binlog_position)));
}
/*
* We have completed the creation of the instance data, so now
@ -424,12 +560,15 @@ unsigned char *defuuid;
sprintf(name, "%s stats", service->name);
hktask_add(name, stats_func, inst, BLR_STATS_FREQ);
}
free(name);
/*
* Now start the replication from the master to MaxScale
*/
blr_start_master(inst);
free(name);
if (inst->master_state == BLRM_UNCONNECTED) {
blr_start_master(inst);
}
return (ROUTER *)inst;
}
@ -461,7 +600,7 @@ ROUTER_SLAVE *slave;
if ((slave = (ROUTER_SLAVE *)calloc(1, sizeof(ROUTER_SLAVE))) == NULL)
{
LOGIF(LD, (skygw_log_write_flush(
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Insufficient memory to create new slave session for binlog router")));
return NULL;
@ -732,9 +871,12 @@ struct tm tm;
min10 /= 10.0;
min5 /= 5.0;
dcb_printf(dcb, "\tMaster connection DCB: %p\n",
if (router_inst->master)
dcb_printf(dcb, "\tMaster connection DCB: %p\n",
router_inst->master);
else
dcb_printf(dcb, "\tMaster connection DCB: 0x0\n");
dcb_printf(dcb, "\tMaster connection state: %s\n",
blrm_states[router_inst->master_state]);
@ -781,7 +923,7 @@ struct tm tm;
dcb_printf(dcb, "\tNumber of residual data packets: %u\n",
router_inst->stats.n_residuals);
dcb_printf(dcb, "\tAverage events per packet %.1f\n",
(double)router_inst->stats.n_binlogs / router_inst->stats.n_reads);
router_inst->stats.n_reads != 0 ? ((double)router_inst->stats.n_binlogs / router_inst->stats.n_reads) : 0);
dcb_printf(dcb, "\tLast event from master at: %s",
buf);
dcb_printf(dcb, "\t (%d seconds ago)\n",
@ -1047,12 +1189,6 @@ unsigned long mysql_errno;
mysql_errno = (unsigned long) extract_field((uint8_t *)(GWBUF_DATA(message) + 5), 16);
errmsg = extract_message(message);
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, "%s: Master connection error '%s' in state '%s', "
"%sattempting reconnect to master",
router->service->name, errmsg,
blrm_states[router->master_state], msg)));
if (router->master_state < BLRM_BINLOGDUMP || router->master_state != BLRM_SLAVE_STOPPED) {
/* set mysql_errno */
router->m_errno = mysql_errno;
@ -1061,6 +1197,18 @@ unsigned long mysql_errno;
if (router->m_errmsg)
free(router->m_errmsg);
router->m_errmsg = strdup(errmsg);
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, "%s: Master connection error %lu '%s' in state '%s', "
"%sattempting reconnect to master",
router->service->name, mysql_errno, errmsg,
blrm_states[router->master_state], msg)));
} else {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, "%s: Master connection error %lu '%s' in state '%s', "
"%sattempting reconnect to master",
router->service->name, router->m_errno, router->m_errmsg,
blrm_states[router->master_state], msg)));
}
if (errmsg)
@ -1070,7 +1218,7 @@ unsigned long mysql_errno;
LOGFILE_MESSAGE,
"%s: Master %s disconnected after %ld seconds. "
"%d events read.",
router->service->name, router->master->remote,
router->service->name, router->service->dbref->server->name,
time(0) - router->connect_time, router->stats.n_binlogs_ses)));
blr_master_reconnect(router);
}
@ -1308,3 +1456,234 @@ GWBUF *errbuf = NULL;
return dcb->func.write(dcb, errbuf);
}
/**
* Config item handler for the ini file reader
*
* @param userdata The config context element
* @param section The config file section
* @param name The Parameter name
* @param value The Parameter value
* @return zero on error
*/
static int
blr_handler_config(void *userdata, const char *section, const char *name, const char *value)
{
ROUTER_INSTANCE *inst = (ROUTER_INSTANCE *) userdata;
SERVICE *service;
service = inst->service;
if (strcasecmp(section, "binlog_configuration") == 0)
{
return blr_handle_config_item(name, value, inst);
} else {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error : master.ini has an invalid section [%s], it should be [binlog_configuration]. Service %s",
section,
service->name)));
return 0;
}
}
/**
* Configuration handler for items in the [binlog_configuration] section
*
* @param name The item name
* @param value The item value
* @param inst The current router instance
* @return 0 on error
*/
static int
blr_handle_config_item(const char *name, const char *value, ROUTER_INSTANCE *inst)
{
SERVICE *service;
service = inst->service;
if (strcmp(name, "master_host") == 0) {
server_update_address(service->dbref->server, (char *)value);
} else if (strcmp(name, "master_port") == 0) {
server_update_port(service->dbref->server, (short)atoi(value));
} else if (strcmp(name, "filestem") == 0) {
free(inst->fileroot);
inst->fileroot = strdup(value);
} else if (strcmp(name, "master_user") == 0) {
if (inst->user)
free(inst->user);
inst->user = strdup(value);
} else if (strcmp(name, "master_password") == 0) {
if (inst->password)
free(inst->password);
inst->password = strdup(value);
} else {
return 0;
}
return 1;
}
/**
* Add the service user to mysql dbusers (service->users)
* via mysql_users_alloc and add_mysql_users_with_host_ipv4
* User is added for '%' and 'localhost' hosts
*
* @param service The current service
* @return 0 on success, 1 on failure
*/
static int
blr_set_service_mysql_user(SERVICE *service) {
char *dpwd = NULL;
char *newpasswd = NULL;
char *service_user = NULL;
char *service_passwd = NULL;
if (serviceGetUser(service, &service_user, &service_passwd) == 0) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"failed to get service user details for service %s",
service->name)));
return 1;
}
dpwd = decryptPassword(service->credentials.authdata);
if (!dpwd) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"decrypt password failed for service user %s, service %s",
service_user,
service->name)));
return 1;
}
newpasswd = create_hex_sha1_sha1_passwd(dpwd);
if (!newpasswd) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"create hex_sha1_sha1_password failed for service user %s",
service_user)));
return 1;
}
/* add service user for % and localhost */
(void)add_mysql_users_with_host_ipv4(service->users, service->credentials.name, "%", newpasswd, "Y", "");
(void)add_mysql_users_with_host_ipv4(service->users, service->credentials.name, "localhost", newpasswd, "Y", "");
free(newpasswd);
free(dpwd);
return 0;
}
/* -1 is failure, >0 is success */
int
blr_load_dbusers(ROUTER_INSTANCE *router)
{
int loaded;
char path[4097];
SERVICE *service;
service = router->service;
/* File path for router cached authentication data */
strcpy(path, router->binlogdir);
strncat(path, "/cache", 4096);
strncat(path, "/dbusers", 4096);
/* Try loading dbusers from configured backends */
loaded = load_mysql_users(service);
if (loaded < 0)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to load users for service %s",
service->name)));
/* Try loading authentication data from file cache */
loaded = dbusers_load(router->service->users, path);
if (loaded != -1)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Service %s, Using cached credential information file %s.",
service->name,
path)));
} else {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error: Service %s, Unable to read cache credential information from %s.",
" No database user added to service users table.",
service->name,
path)));
}
} else {
/* don't update cache if no user was loaded */
if (loaded == 0)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Service %s: failed to load any user "
"information. Authentication will "
"probably fail as a result.",
service->name)));
} else {
/* update cached data */
blr_save_dbusers(router);
}
}
/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
* This way MaxScale could try reloading users' just after startup
*/
service->rate_limit.last=time(NULL) - USERS_REFRESH_TIME;
service->rate_limit.nloads=1;
return loaded;
}
/* -1 is error, >= 0 is ok */
int
blr_save_dbusers(ROUTER_INSTANCE *router)
{
SERVICE *service;
char path[4097];
int mkdir_rval;
service = router->service;
/* File path for router cached authentication data */
strcpy(path, router->binlogdir);
strncat(path, "/cache", 4096);
/* check and create dir */
if (access(path, R_OK) == -1)
{
mkdir_rval = mkdir(path, 0700);
}
if (mkdir_rval == -1)
{
skygw_log_write(LOGFILE_ERROR,
"Error : Service %s, Failed to create directory '%s': [%d] %s",
service->name,
path,
errno,
strerror(errno));
return -1;
}
/* set cache file name */
strncat(path, "/dbusers", 4096);
return dbusers_save(service->users, path);
}

View File

@ -28,6 +28,8 @@
* 08/06/2015 Massimiliano Pinto Addition of blr_cache_read_master_data()
* 15/06/2015 Massimiliano Pinto Addition of blr_file_get_next_binlogname()
* 23/06/2015 Massimiliano Pinto Addition of blr_file_use_binlog, blr_file_create_binlog
* 29/06/2015 Massimiliano Pinto Addition of blr_file_write_master_config()
* Cache directory is now 'cache' under router->binlogdir
*
* @endverbatim
*/
@ -66,6 +68,7 @@ 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);
void blr_file_use_binlog(ROUTER_INSTANCE *router, char *file);
int blr_file_write_master_config(ROUTER_INSTANCE *router, char *error);
/**
* Initialise the binlog file for this instance. MaxScale will look
@ -95,7 +98,7 @@ struct dirent *dp;
strncat(path, router->service->name,PATH_MAX);
if (access(path, R_OK) == -1)
mkdir(path, 0777);
mkdir(path, 0700);
router->binlogdir = strdup(path);
}
@ -659,6 +662,8 @@ struct stat statb;
* Write the response packet to a cache file so that MaxScale can respond
* even if there is no master running when MaxScale starts.
*
* cache dir is 'cache' under router->binlogdir
*
* @param router The instance of the router
* @param response The name of the response, used to name the cached file
* @param buf The buffer to written to the cache
@ -669,25 +674,21 @@ blr_cache_response(ROUTER_INSTANCE *router, char *response, GWBUF *buf)
char path[4097], *ptr;
int fd;
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strncat(path, "/", 4096);
strncat(path, router->service->name, 4096);
strncpy(path, router->binlogdir, 4096);
strncat(path, "/cache", 4096);
if (access(path, R_OK) == -1) {
int mkdir_ret;
mkdir_ret = mkdir(path, 0700);
}
if (access(path, R_OK) == -1)
mkdir(path, 0777);
strncat(path, "/.cache", 4096);
if (access(path, R_OK) == -1)
mkdir(path, 0777);
strncat(path, "/", 4096);
strncat(path, response, 4096);
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
return;
write(fd, GWBUF_DATA(buf), GWBUF_LENGTH(buf));
close(fd);
}
@ -696,6 +697,8 @@ int fd;
* the router to start and serve any binlogs it already has on disk
* if the master is not available.
*
* cache dir is 'cache' under router->binlogdir
*
* @param router The router instance structure
* @param response The name of the response
* @return A pointer to a GWBUF structure
@ -708,14 +711,9 @@ char path[4097], *ptr;
int fd;
GWBUF *buf;
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strncpy(path, router->binlogdir, 4096);
strncat(path, "/cache", 4096);
strncat(path, "/", 4096);
strncat(path, router->service->name, 4096);
strncat(path, "/.cache/", 4096);
strncat(path, response, 4096);
if ((fd = open(path, O_RDONLY)) == -1)
@ -798,7 +796,9 @@ int filenum;
if ((sptr = strrchr(router->binlog_name, '.')) == NULL)
return 0;
filenum = atoi(sptr+1) + 1;
filenum = atoi(sptr+1);
if (filenum)
filenum++;
return filenum;
}
@ -826,3 +826,73 @@ blr_file_use_binlog(ROUTER_INSTANCE *router, char *file)
{
return blr_file_append(router, file);
}
/**
* Write a new ini file with master configuration
*
* File is 'inst->binlogdir/master.ini.tmp'
* When done it's renamed to 'inst->binlogdir/master.ini'
*
* @param router The current router instance
* @param error Preallocated error message
* @return 0 on success, >0 on failure
*
*/
int
blr_file_write_master_config(ROUTER_INSTANCE *router, char *error) {
char *master_host;
int master_port;
char *filestem;
char *master_user;
char *master_password;
char *section = "binlog_configuration";
FILE *config_file;
int rc;
char path[(PATH_MAX - 15) + 1] = "";
char filename[(PATH_MAX - 4) + 1] = "";
char tmp_file[PATH_MAX + 1] = "";
strncpy(path, router->binlogdir, (PATH_MAX - 15));
snprintf(filename,(PATH_MAX - 4), "%s/master.ini", path);
snprintf(tmp_file, (PATH_MAX -4), filename);
strcat(tmp_file, ".tmp");
/* get data from current configuration */
master_host = router->service->dbref->server->name;
master_port = router->service->dbref->server->port;
master_user = router->user;
master_password= router->password;
filestem = router->fileroot;
/* open file for writing */
config_file = fopen(tmp_file,"wb");
if (config_file == NULL) {
snprintf(error, BINLOG_ERROR_MSG_LEN, "%s, errno %u", strerror(errno), errno);
return 2;
}
/* write ini file section */
fprintf(config_file,"[%s]\n", section);
/* write ini file key=value */
fprintf(config_file,"master_host=%s\n", master_host);
fprintf(config_file,"master_port=%d\n", master_port);
fprintf(config_file,"master_user=%s\n", master_user);
fprintf(config_file,"master_password=%s\n", master_password);
fprintf(config_file,"filestem=%s\n", filestem);
fclose(config_file);
/* rename tmp file to right filename */
rc = rename(tmp_file, filename);
if (rc == -1) {
snprintf(error, BINLOG_ERROR_MSG_LEN, "%s, errno %u", strerror(errno), errno);
return 3;
}
return 0;
}

View File

@ -43,11 +43,14 @@
* 15/06/2015 Massimiliano Pinto Added constraints to CHANGE MASTER TO MASTER_LOG_FILE/POS
* 23/06/2015 Massimiliano Pinto Added utility routines for blr_handle_change_master
* Call create/use binlog in blr_start_slave() (START SLAVE)
* 29/06/2015 Massimiliano Pinto Successfully CHANGE MASTER results in updating master.ini
* in blr_handle_change_master()
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <service.h>
#include <server.h>
@ -65,9 +68,12 @@
#include <version.h>
#include <zlib.h>
extern int load_mysql_users(SERVICE *service);
extern int blr_save_dbusers(ROUTER_INSTANCE *router);
extern void blr_master_close(ROUTER_INSTANCE* router);
extern void blr_file_use_binlog(ROUTER_INSTANCE *router, char *file);
extern int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file);
extern int blr_file_write_master_config(ROUTER_INSTANCE *router, char *error);
int blr_file_get_next_binlogname(ROUTER_INSTANCE *router);
static uint32_t extract_field(uint8_t *src, int bits);
static void encode_value(unsigned char *data, unsigned int value, int len);
@ -106,6 +112,8 @@ static char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char
static void blr_master_get_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *current_master);
static void blr_master_free_config(MASTER_SERVER_CFG *current_master);
static void blr_master_restore_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *current_master);
static void blr_master_set_empty_config(ROUTER_INSTANCE *router);
static void blr_master_apply_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *prev_master);
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -146,7 +154,21 @@ blr_slave_request(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
return blr_slave_query(router, slave, queue);
break;
case COM_REGISTER_SLAVE:
return blr_slave_register(router, slave, queue);
if (router->master_state == BLRM_UNCONFIGURED) {
slave->state = BLRS_ERRORED;
blr_slave_send_error_packet(slave,
"Binlog router is not yet configured for replication", (unsigned int) 1597, NULL);
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"%s: Slave %s: Binlog router is not yet configured for replication",
router->service->name,
slave->dcb->remote)));
dcb_close(slave->dcb);
return 1;
} else {
return blr_slave_register(router, slave, queue);
}
break;
case COM_BINLOG_DUMP:
return blr_slave_binlog_dump(router, slave, queue);
@ -358,7 +380,13 @@ int query_len;
else if (strcasecmp(word, "STATUS") == 0)
{
free(query_text);
return blr_slave_send_master_status(router, slave);
/* if state is BLRM_UNCONFIGURED return empty result */
if (router->master_state > BLRM_UNCONFIGURED)
return blr_slave_send_master_status(router, slave);
else
return blr_slave_send_ok(router, slave);
}
}
else if (strcasecmp(word, "SLAVE") == 0)
@ -372,12 +400,20 @@ int query_len;
else if (strcasecmp(word, "STATUS") == 0)
{
free(query_text);
return blr_slave_send_slave_status(router, slave);
/* if state is BLRM_UNCONFIGURED return empty result */
if (router->master_state > BLRM_UNCONFIGURED)
return blr_slave_send_slave_status(router, slave);
else
return blr_slave_send_ok(router, slave);
}
else if (strcasecmp(word, "HOSTS") == 0)
{
free(query_text);
return blr_slave_send_slave_hosts(router, slave);
/* if state is BLRM_UNCONFIGURED return empty result */
if (router->master_state > BLRM_UNCONFIGURED)
return blr_slave_send_slave_hosts(router, slave);
else
return blr_slave_send_ok(router, slave);
}
}
}
@ -437,6 +473,79 @@ int query_len;
return blr_slave_replay(router, slave, router->saved_master.utf8);
}
}
} /* RESET current configured master */
else if (strcasecmp(query_text, "RESET") == 0)
{
if ((word = strtok_r(NULL, sep, &brkb)) == NULL)
{
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR, "%s: Incomplete RESET command.",
router->service->name)));
}
else if (strcasecmp(word, "SLAVE") == 0)
{
free(query_text);
if (router->master_state == BLRM_SLAVE_STOPPED) {
char path[4097] = "";
char error_string[BINLOG_ERROR_MSG_LEN + 1] = "";
MASTER_SERVER_CFG *current_master = NULL;
int removed_cfg = 0;
/* save current replication parameters */
current_master = (MASTER_SERVER_CFG *)calloc(1, sizeof(MASTER_SERVER_CFG));
if (!current_master) {
snprintf(error_string, BINLOG_ERROR_MSG_LEN, "error allocating memory for blr_master_get_config");
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error_string)));
blr_slave_send_error_packet(slave, error_string, (unsigned int)1201, NULL);
return 1;
}
/* get current data */
blr_master_get_config(router, current_master);
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, "%s: 'RESET SLAVE executed'. Previous state MASTER_HOST='%s', MASTER_PORT=%i, MASTER_LOG_FILE='%s', MASTER_LOG_POS=%lu, MASTER_USER='%s', MASTER_PASSWORD='%s'",
router->service->name,
current_master->host,
current_master->port,
current_master->logfile,
current_master->pos,
current_master->user,
current_master->password)));
/* remove master.ini */
strncpy(path, router->binlogdir, PATH_MAX);
strncat(path,"/master.ini", PATH_MAX);
/* remove master.ini */
removed_cfg = unlink(path);
if (removed_cfg == -1) {
snprintf(error_string, BINLOG_ERROR_MSG_LEN, "Error removing %s, %s, errno %u", path, strerror(errno), errno);
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error_string)));
}
spinlock_acquire(&router->lock);
router->master_state = BLRM_UNCONFIGURED;
blr_master_set_empty_config(router);
blr_master_free_config(current_master);
spinlock_release(&router->lock);
if (removed_cfg == -1) {
blr_slave_send_error_packet(slave, error_string, (unsigned int)1201, NULL);
return 1;
} else {
return blr_slave_send_ok(router, slave);
}
} else {
blr_slave_send_error_packet(slave, "This operation cannot be performed with a running slave; run STOP SLAVE first", (unsigned int)1198, NULL);
return 1;
}
}
}
/* start replication from the current configured master */
else if (strcasecmp(query_text, "START") == 0)
@ -451,7 +560,6 @@ int query_len;
free(query_text);
return blr_start_slave(router, slave);
}
}
/* stop replication from the current master*/
else if (strcasecmp(query_text, "STOP") == 0)
@ -477,7 +585,7 @@ int query_len;
}
else if (strcasecmp(word, "MASTER") == 0)
{
if (router->master_state != BLRM_SLAVE_STOPPED)
if (router->master_state != BLRM_SLAVE_STOPPED && router->master_state != BLRM_UNCONFIGURED)
{
free(query_text);
blr_slave_send_error_packet(slave, "Cannot change master with a running slave; run STOP SLAVE first", (unsigned int)1198, NULL);
@ -487,16 +595,73 @@ int query_len;
{
int rc;
char error_string[BINLOG_ERROR_MSG_LEN + 1] = "";
MASTER_SERVER_CFG *current_master = NULL;
current_master = (MASTER_SERVER_CFG *)calloc(1, sizeof(MASTER_SERVER_CFG));
if (!current_master) {
free(query_text);
strcpy(error_string, "Error allocating memory for blr_master_get_config");
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error_string)));
blr_slave_send_error_packet(slave, error_string, (unsigned int)1201, NULL);
return 1;
}
blr_master_get_config(router, current_master);
rc = blr_handle_change_master(router, brkb, error_string);
free(query_text);
if (rc < 0) {
/* CHANGE MASTER TO has failed */
blr_slave_send_error_packet(slave, error_string, (unsigned int)1234, "42000");
blr_master_free_config(current_master);
return 1;
} else
} else {
int ret;
char error[BINLOG_ERROR_MSG_LEN + 1];
/* Write/Update master config into master.ini file */
ret = blr_file_write_master_config(router, error);
if (ret) {
/* file operation failure: restore config */
spinlock_acquire(&router->lock);
blr_master_apply_config(router, current_master);
blr_master_free_config(current_master);
spinlock_release(&router->lock);
snprintf(error_string, BINLOG_ERROR_MSG_LEN, "Error writing into %s/master.ini: %s", router->binlogdir, error);
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR, "%s: %s",
router->service->name, error_string)));
blr_slave_send_error_packet(slave, error_string, (unsigned int)1201, NULL);
return 1;
}
/**
* check if router is BLRM_UNCONFIGURED
* and change state to BLRM_SLAVE_STOPPED
*/
if (rc == 1 || router->master_state == BLRM_UNCONFIGURED) {
spinlock_acquire(&router->lock);
router->master_state = BLRM_SLAVE_STOPPED;
spinlock_release(&router->lock);
}
blr_master_free_config(current_master);
return blr_slave_send_ok(router, slave);
}
}
}
}
@ -552,8 +717,12 @@ blr_slave_replay(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *master)
{
GWBUF *clone;
if (router->master_state == BLRM_UNCONFIGURED)
return blr_slave_send_ok(router, slave);
if (!master)
return 0;
if ((clone = gwbuf_clone(master)) != NULL)
{
return slave->dcb->func.write(slave->dcb, clone);
@ -2243,8 +2412,9 @@ uint8_t *ptr;
/**
* Stop current replication from master
*
* @param router The binlog router instance
* @param slave The slave server to which we are sending the response*
* @param router The binlog router instance
* @param slave The slave server to which we are sending the response*
* @return Always 1 for error, for send_ok the bytes sent
*
*/
@ -2253,51 +2423,64 @@ blr_stop_slave(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave)
{
GWBUF *ptr;
if (router->master_state != BLRM_SLAVE_STOPPED) {
/* if unconfigured return an error */
if (router->master_state == BLRM_UNCONFIGURED) {
blr_slave_send_error_packet(slave, "The server is not configured as slave; fix in config file or with CHANGE MASTER TO", (unsigned int)1200, NULL);
if (router->master)
if (router->master->fd != -1 && router->master->state == DCB_STATE_POLLING)
blr_master_close(router);
spinlock_acquire(&router->lock);
router->master_state = BLRM_SLAVE_STOPPED;
spinlock_release(&router->lock);
if (router->client)
if (router->client->fd != -1 && router->client->state == DCB_STATE_POLLING)
dcb_close(router->client);
/* Discard the queued residual data */
ptr = router->residual;
while (ptr)
{
ptr = gwbuf_consume(ptr, GWBUF_LENGTH(ptr));
}
router->residual = NULL;
/* Now it is safe to unleash other threads on this router instance */
spinlock_acquire(&router->lock);
router->reconnect_pending = 0;
router->active_logs = 0;
spinlock_release(&router->lock);
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"%s: STOP SLAVE executed by %s@%s. Disconnecting from master %s:%d, read up to log %s, pos %lu",
router->service->name,
slave->dcb->user,
slave->dcb->remote,
router->service->dbref->server->name,
router->service->dbref->server->port,
router->binlog_name, router->binlog_position)));
return blr_slave_send_ok(router, slave);
} else {
blr_slave_send_error_packet(slave, "Slave connection is not running", (unsigned int)1199, NULL);
return 1;
}
/* if already stopped return an error */
if (router->master_state == BLRM_SLAVE_STOPPED) {
blr_slave_send_error_packet(slave, "Slave connection is not running", (unsigned int)1199, NULL);
return 1;
}
if (router->master) {
if (router->master->fd != -1 && router->master->state == DCB_STATE_POLLING) {
blr_master_close(router);
}
}
spinlock_acquire(&router->lock);
router->master_state = BLRM_SLAVE_STOPPED;
spinlock_release(&router->lock);
if (router->client) {
if (router->client->fd != -1 && router->client->state == DCB_STATE_POLLING) {
dcb_close(router->client);
}
}
/* Discard the queued residual data */
ptr = router->residual;
while (ptr)
{
ptr = gwbuf_consume(ptr, GWBUF_LENGTH(ptr));
}
router->residual = NULL;
/* Now it is safe to unleash other threads on this router instance */
spinlock_acquire(&router->lock);
router->reconnect_pending = 0;
router->active_logs = 0;
spinlock_release(&router->lock);
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"%s: STOP SLAVE executed by %s@%s. Disconnecting from master %s:%d, read up to log %s, pos %lu",
router->service->name,
slave->dcb->user,
slave->dcb->remote,
router->service->dbref->server->name,
router->service->dbref->server->port,
router->binlog_name, router->binlog_position)));
return blr_slave_send_ok(router, slave);
}
/**
@ -2305,42 +2488,75 @@ blr_stop_slave(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave)
*
* @param router The binlog router instance
* @param slave The slave server to which we are sending the response
* @return Always 1 for error, for send_ok the bytes sent
*
*/
static int
blr_start_slave(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave)
{
if ( (router->master_state == BLRM_UNCONNECTED) || (router->master_state == BLRM_SLAVE_STOPPED) ) {
char path[4097]="";
int loaded;
spinlock_acquire(&router->lock);
router->master_state = BLRM_UNCONNECTED;
spinlock_release(&router->lock);
/* if unconfigured return an error */
if (router->master_state == BLRM_UNCONFIGURED) {
blr_slave_send_error_packet(slave, "The server is not configured as slave; fix in config file or with CHANGE MASTER TO", (unsigned int)1200, NULL);
/* create a new binlog or just use current one */
if (strcmp(router->prevbinlog, router->binlog_name))
blr_file_new_binlog(router, router->binlog_name);
else
blr_file_use_binlog(router, router->binlog_name);
blr_start_master(router);
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"%s: START SLAVE executed by %s@%s. Trying connection to master %s:%d, binlog %s, pos %lu",
router->service->name,
slave->dcb->user,
slave->dcb->remote,
router->service->dbref->server->name,
router->service->dbref->server->port,
router->binlog_name,
router->binlog_position)));
return blr_slave_send_ok(router, slave);
} else {
blr_slave_send_error_packet(slave, "Slave connection is already running", (unsigned int)1254, NULL);
return 1;
}
/* if running return an error */
if (router->master_state != BLRM_UNCONNECTED && router->master_state != BLRM_SLAVE_STOPPED) {
blr_slave_send_error_packet(slave, "Slave connection is already running", (unsigned int)1254, NULL);
return 1;
}
spinlock_acquire(&router->lock);
router->master_state = BLRM_UNCONNECTED;
spinlock_release(&router->lock);
/* create a new binlog or just use current one */
if (strcmp(router->prevbinlog, router->binlog_name))
blr_file_new_binlog(router, router->binlog_name);
else
blr_file_use_binlog(router, router->binlog_name);
blr_start_master(router);
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"%s: START SLAVE executed by %s@%s. Trying connection to master %s:%d, binlog %s, pos %lu",
router->service->name,
slave->dcb->user,
slave->dcb->remote,
router->service->dbref->server->name,
router->service->dbref->server->port,
router->binlog_name,
router->binlog_position)));
/* File path for router cached authentication data */
strcpy(path, router->binlogdir);
strncat(path, "/cache", 4096);
strncat(path, "/dbusers", 4096);
/* Try loading dbusers from configured backends */
loaded = load_mysql_users(router->service);
if (loaded < 0)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to load users for service %s",
router->service->name)));
} else {
/* update cached data */
if (loaded > 0)
blr_save_dbusers(router);
}
return blr_slave_send_ok(router, slave);
}
/**
@ -2405,6 +2621,7 @@ char *get_change_master_option(char *input, char *option_field) {
extern char *strcasestr();
char *option = NULL;
char *ptr = NULL;
char *new_ptr = NULL;
ptr = strcasestr(input, option_field);
if (ptr) {
char *end;
@ -2412,9 +2629,11 @@ char *get_change_master_option(char *input, char *option_field) {
end = strchr(option, ',');
if (end)
*end = '\0';
new_ptr = strdup(option);
free(option);
}
return option;
return new_ptr;
}
/**
@ -2467,13 +2686,31 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
blr_set_master_port(router, command);
/**
* Check for binlog filename in command
* Change the binlog filename to request from master
* New binlog file could be the next one or current one
*/
master_logfile = blr_set_master_logfile(router, command, error);
if (master_logfile == NULL && router->master_state == BLRM_UNCONFIGURED) {
strcpy(error, "Router is not configured for master connection, MASTER_LOG_FILE is required");
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error)));
/* restore previous master_host and master_port */
blr_master_restore_config(router, current_master);
spinlock_release(&router->lock);
return -1;
}
/**
* If MASTER_LOG_FILE is not set
* and master connection is configured
* set master_logfile to current binlog_name
*/
if (master_logfile == NULL) {
/* if error return */
/* if errors return */
if (strlen(error)) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error)));
@ -2485,12 +2722,17 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
return -1;
} else {
/* binlog file not set by CHANGE MASTER, use current binlog */
master_logfile = strdup(router->binlog_name);
/* If not set by CHANGE MASTER, use current binlog if configured */
if (router->master_state != BLRM_UNCONFIGURED) {
master_logfile = strdup(router->binlog_name);
}
}
}
/* Change the position in the current or new binlog filename */
/**
* Change the position in the current or new binlog filename
*/
if (master_log_pos == NULL) {
pos = 0;
} else {
@ -2498,8 +2740,12 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
pos = atoll(passed_pos);
}
/* if binlog name has changed to next one only position 4 is allowed */
if (strcmp(master_logfile, router->binlog_name)) {
/**
* If master connection is configured check new binlog name:
* If binlog name has changed to next one only position 4 is allowed
*/
if (strcmp(master_logfile, router->binlog_name) && router->master_state != BLRM_UNCONFIGURED) {
int return_error = 0;
if (master_log_pos == NULL) {
snprintf(error, BINLOG_ERROR_MSG_LEN, "Please provide an explicit MASTER_LOG_POS for new MASTER_LOG_FILE %s: "
@ -2548,26 +2794,47 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
router->binlog_position = 4;
LOGIF(LT, (skygw_log_write(LOGFILE_TRACE, "%s: New MASTER_LOG_FILE is [%s]",
router->service->name,
router->binlog_name)));
if (master_log_pos)
free(master_log_pos);
if (master_logfile)
free(master_logfile);
LOGIF(LT, (skygw_log_write(LOGFILE_TRACE, "%s: New MASTER_LOG_FILE is [%s]",
router->service->name,
router->binlog_name)));
}
} else {
/* Position cannot be different from current pos */
if (pos > 0 && pos != router->binlog_position) {
/**
* Same binlog or master connection not configured
* Position cannot be different from current pos or 4 (if BLRM_UNCONFIGURED)
*/
int return_error = 0;
snprintf(error, BINLOG_ERROR_MSG_LEN, "Can not set MASTER_LOG_POS to %s: "
"Permitted binlog pos is %lu. Current master_log_file=%s, master_log_pos=%lu",
passed_pos,
router->binlog_position,
router->binlog_name,
router->binlog_position);
if (router->master_state == BLRM_UNCONFIGURED) {
if (pos && pos != 4) {
snprintf(error, BINLOG_ERROR_MSG_LEN, "Can not set MASTER_LOG_POS to %s: "
"Permitted binlog pos is 4. Specified master_log_file=%s",
passed_pos,
master_logfile);
return_error = 1;
}
} else {
if (pos > 0 && pos != router->binlog_position) {
snprintf(error, BINLOG_ERROR_MSG_LEN, "Can not set MASTER_LOG_POS to %s: "
"Permitted binlog pos is %lu. Current master_log_file=%s, master_log_pos=%lu",
passed_pos,
router->binlog_position,
router->binlog_name,
router->binlog_position);
return_error = 1;
}
}
/* log error and return */
if (return_error) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error)));
if (master_log_pos)
@ -2582,7 +2849,24 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
return -1;
} else {
/* pos unchanged, binlogfile unchanged */
/**
* no pos change, set it to 4 if BLRM_UNCONFIGURED
* Also set binlog name if UNCOFIGURED
*/
if (router->master_state == BLRM_UNCONFIGURED) {
router->binlog_position = 4;
memset(router->binlog_name, '\0', sizeof(router->binlog_name));
strncpy(router->binlog_name, master_logfile, BINLOG_FNAMELEN);
LOGIF(LT, (skygw_log_write(LOGFILE_TRACE, "%s: New MASTER_LOG_FILE is [%s]",
router->service->name,
router->binlog_name)));
}
LOGIF(LT, (skygw_log_write(LOGFILE_TRACE, "%s: New MASTER_LOG_POS is [%u]",
router->service->name,
router->binlog_position)));
if (master_log_pos)
free(master_log_pos);
if (master_logfile)
@ -2590,10 +2874,6 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
}
}
LOGIF(LT, (skygw_log_write(LOGFILE_TRACE, "%s: New MASTER_LOG_POS is [%u]",
router->service->name,
router->binlog_position)));
/* Change the replication user */
if (master_user) {
char *ptr;
@ -2658,9 +2938,8 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
blr_master_free_config(current_master);
/* force stopped state */
router->master_state = BLRM_SLAVE_STOPPED;
if (router->master_state == BLRM_UNCONFIGURED)
change_binlog = 1;
spinlock_release(&router->lock);
@ -2748,24 +3027,24 @@ blr_set_master_port(ROUTER_INSTANCE *router, char *command) {
* @param router Current router instance
* @param command CHANGE MASTER TO command
* @param error The error msg for command
* @return New binlog file or NULL otherwise
* @return New binlog file or NULL on error
*/
char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error) {
int change_binlog = 0;
char *new_binlog_file = NULL;
char *master_logfile = get_change_master_option(command, "MASTER_LOG_FILE");
char *logfile = get_change_master_option(command, "MASTER_LOG_FILE");
if (master_logfile) {
if (logfile) {
char *ptr;
char *end;
long next_binlog_seqname;
ptr = strchr(master_logfile, '\'');
ptr = strchr(logfile, '\'');
if (ptr)
ptr++;
else
ptr = master_logfile + 16;
ptr = logfile + 16;
end = strchr(ptr+1, '\'');
@ -2781,13 +3060,30 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
router->service->name, ptr,
router->fileroot);
free(master_logfile);
free(logfile);
return NULL;
}
end++;
if (router->master_state == BLRM_UNCONFIGURED) {
char *stem_end;
stem_end = strrchr(ptr, '.');
/* set filestem */
if (stem_end) {
if (router->fileroot)
free(router->fileroot);
router->fileroot = strndup(ptr, stem_end-ptr);
}
/* return new filename */
new_binlog_file = strdup(ptr);
free(logfile);
return new_binlog_file;
}
/* get next binlog file name, assuming filestem is the same */
next_binlog_seqname = blr_file_get_next_binlogname(router);
@ -2797,7 +3093,7 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
router->service->name,
router->binlog_name);
free(master_logfile);
free(logfile);
return NULL;
}
@ -2822,7 +3118,7 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
router->binlog_name,
router->binlog_position);
free(master_logfile);
free(logfile);
return NULL;
}
@ -2834,7 +3130,7 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
/* allocate new filename */
new_binlog_file = strdup(ptr);
free(master_logfile);
free(logfile);
}
return new_binlog_file;
@ -2854,6 +3150,7 @@ blr_master_get_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *curr_master) {
strncpy(curr_master->logfile, router->binlog_name, BINLOG_FNAMELEN);
curr_master->user = strdup(router->user);
curr_master->password = strdup(router->password);
curr_master->filestem = strdup(router->fileroot);
}
/**
@ -2869,6 +3166,8 @@ blr_master_free_config(MASTER_SERVER_CFG *master_cfg) {
free(master_cfg->user);
if (master_cfg->password)
free(master_cfg->password);
if (master_cfg->filestem)
free(master_cfg->filestem);
free(master_cfg);
}
@ -2886,3 +3185,44 @@ blr_master_restore_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *prev_maste
blr_master_free_config(prev_master);
}
/**
* Set all the master configuration fields to empty values
*
* @param router Current router instance
*/
static void
blr_master_set_empty_config(ROUTER_INSTANCE *router) {
server_update_address(router->service->dbref->server, "none");
server_update_port(router->service->dbref->server, (unsigned short)1234);
router->binlog_position = 4;
strcpy(router->binlog_name, "");
}
/**
* Restore all master configuration values
*
* @param router Current router instance
* @param prev_master Previous saved master configuration
*/
static void
blr_master_apply_config(ROUTER_INSTANCE *router, MASTER_SERVER_CFG *prev_master) {
server_update_address(router->service->dbref->server, prev_master->host);
server_update_port(router->service->dbref->server, prev_master->port);
router->binlog_position = prev_master->pos;
strcpy(router->binlog_name, prev_master->logfile);
if (router->user) {
free(router->user);
router->user = strdup(prev_master->user);
}
if (router->password) {
free(router->password);
router->password = strdup(prev_master->password);
}
if (router->fileroot) {
free(router->fileroot);
router->fileroot = strdup(prev_master->filestem);
}
}