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:
@ -30,6 +30,7 @@
|
|||||||
* 05/06/15 Massimiliano Pinto Addition of m_errno, m_errmsg fields
|
* 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
|
* 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
|
* 23/06/15 Massimiliano Pinto Addition of MASTER_SERVER_CFG struct
|
||||||
|
* 24/06/15 Massimiliano Pinto Added BLRM_UNCONFIGURED state
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -75,7 +76,7 @@
|
|||||||
#define BLR_MAX_BACKOFF 60
|
#define BLR_MAX_BACKOFF 60
|
||||||
|
|
||||||
/* max size for error message returned to client */
|
/* 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
|
* Some useful macros for examining the MySQL Response packets
|
||||||
@ -95,6 +96,7 @@ typedef struct master_server_config {
|
|||||||
uint64_t pos;
|
uint64_t pos;
|
||||||
char *user;
|
char *user;
|
||||||
char *password;
|
char *password;
|
||||||
|
char *filestem;
|
||||||
} MASTER_SERVER_CFG;
|
} MASTER_SERVER_CFG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,31 +315,32 @@ typedef struct router_instance {
|
|||||||
/**
|
/**
|
||||||
* State machine for the master to MaxScale replication
|
* State machine for the master to MaxScale replication
|
||||||
*/
|
*/
|
||||||
#define BLRM_UNCONNECTED 0x0000
|
#define BLRM_UNCONFIGURED 0x0000
|
||||||
#define BLRM_CONNECTING 0x0001
|
#define BLRM_UNCONNECTED 0x0001
|
||||||
#define BLRM_AUTHENTICATED 0x0002
|
#define BLRM_CONNECTING 0x0002
|
||||||
#define BLRM_TIMESTAMP 0x0003
|
#define BLRM_AUTHENTICATED 0x0003
|
||||||
#define BLRM_SERVERID 0x0004
|
#define BLRM_TIMESTAMP 0x0004
|
||||||
#define BLRM_HBPERIOD 0x0005
|
#define BLRM_SERVERID 0x0005
|
||||||
#define BLRM_CHKSUM1 0x0006
|
#define BLRM_HBPERIOD 0x0006
|
||||||
#define BLRM_CHKSUM2 0x0007
|
#define BLRM_CHKSUM1 0x0007
|
||||||
#define BLRM_GTIDMODE 0x0008
|
#define BLRM_CHKSUM2 0x0008
|
||||||
#define BLRM_MUUID 0x0009
|
#define BLRM_GTIDMODE 0x0009
|
||||||
#define BLRM_SUUID 0x000A
|
#define BLRM_MUUID 0x000A
|
||||||
#define BLRM_LATIN1 0x000B
|
#define BLRM_SUUID 0x000B
|
||||||
#define BLRM_UTF8 0x000C
|
#define BLRM_LATIN1 0x000C
|
||||||
#define BLRM_SELECT1 0x000D
|
#define BLRM_UTF8 0x000D
|
||||||
#define BLRM_SELECTVER 0x000E
|
#define BLRM_SELECT1 0x000E
|
||||||
#define BLRM_SELECTVERCOM 0x000F
|
#define BLRM_SELECTVER 0x000F
|
||||||
#define BLRM_SELECTHOSTNAME 0x0010
|
#define BLRM_SELECTVERCOM 0x0010
|
||||||
#define BLRM_MAP 0x0011
|
#define BLRM_SELECTHOSTNAME 0x0011
|
||||||
#define BLRM_REGISTER 0x0012
|
#define BLRM_MAP 0x0012
|
||||||
#define BLRM_BINLOGDUMP 0x0013
|
#define BLRM_REGISTER 0x0013
|
||||||
#define BLRM_SLAVE_STOPPED 0x0014
|
#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",
|
"Server ID retrieval", "HeartBeat Period setup", "binlog checksum config",
|
||||||
"binlog checksum rerieval", "GTID Mode retrieval", "Master UUID retrieval",
|
"binlog checksum rerieval", "GTID Mode retrieval", "Master UUID retrieval",
|
||||||
"Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",
|
"Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",
|
||||||
|
|||||||
@ -35,6 +35,9 @@
|
|||||||
* 02/04/2014 Mark Riddoch Initial implementation
|
* 02/04/2014 Mark Riddoch Initial implementation
|
||||||
* 17/02/2015 Massimiliano Pinto Addition of slave port and username in diagnostics
|
* 17/02/2015 Massimiliano Pinto Addition of slave port and username in diagnostics
|
||||||
* 18/02/2015 Massimiliano Pinto Addition of dcb_close in closeSession
|
* 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
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -59,6 +62,8 @@
|
|||||||
#include <log_manager.h>
|
#include <log_manager.h>
|
||||||
|
|
||||||
#include <mysql_client_server_protocol.h>
|
#include <mysql_client_server_protocol.h>
|
||||||
|
#include <ini.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
extern int lm_enabled_logfiles_bitmask;
|
extern int lm_enabled_logfiles_bitmask;
|
||||||
extern size_t log_ses_count[];
|
extern size_t log_ses_count[];
|
||||||
@ -85,7 +90,14 @@ static void errorReply(
|
|||||||
DCB *backend_dcb,
|
DCB *backend_dcb,
|
||||||
error_action_t action,
|
error_action_t action,
|
||||||
bool *succp);
|
bool *succp);
|
||||||
|
|
||||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
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 */
|
/** The module object definition */
|
||||||
@ -168,6 +180,9 @@ ROUTER_INSTANCE *inst;
|
|||||||
char *value, *name;
|
char *value, *name;
|
||||||
int i;
|
int i;
|
||||||
unsigned char *defuuid;
|
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) {
|
if ((inst = calloc(1, sizeof(ROUTER_INSTANCE))) == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -186,7 +201,7 @@ unsigned char *defuuid;
|
|||||||
inst->master_chksum = true;
|
inst->master_chksum = true;
|
||||||
inst->master_uuid = NULL;
|
inst->master_uuid = NULL;
|
||||||
|
|
||||||
inst->master_state = BLRM_UNCONNECTED;
|
inst->master_state = BLRM_UNCONFIGURED;
|
||||||
inst->master = NULL;
|
inst->master = NULL;
|
||||||
inst->client = NULL;
|
inst->client = NULL;
|
||||||
|
|
||||||
@ -223,20 +238,17 @@ unsigned char *defuuid;
|
|||||||
* the master from which we replicate binlog records. Therefore check
|
* the master from which we replicate binlog records. Therefore check
|
||||||
* that only one server has been defined.
|
* 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(
|
LOGIF(LE, (skygw_log_write(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Exactly one database server may be "
|
"Error : Exactly one database server may be "
|
||||||
"for use with the binlog router.")));
|
"for use with the binlog router.")));
|
||||||
|
/* report as error whether a server is defined in the service */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process the options.
|
* Process the options.
|
||||||
* We have an array of attrbute values passed to us that we must
|
* We have an array of attrbute values passed to us that we must
|
||||||
@ -380,6 +392,117 @@ unsigned char *defuuid;
|
|||||||
|
|
||||||
inst->binlog_position = 0;
|
inst->binlog_position = 0;
|
||||||
strcpy(inst->binlog_name, "");
|
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
|
* Read any cached response messages
|
||||||
@ -389,20 +512,33 @@ unsigned char *defuuid;
|
|||||||
/*
|
/*
|
||||||
* Initialise the binlog file and position
|
* Initialise the binlog file and position
|
||||||
*/
|
*/
|
||||||
if (blr_file_init(inst) == 0)
|
if (inst->master_state == BLRM_UNCONNECTED) {
|
||||||
{
|
if (blr_file_init(inst) == 0)
|
||||||
LOGIF(LE, (skygw_log_write(
|
{
|
||||||
LOGFILE_ERROR,
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
"%s: Service not started due to lack of binlog directory.",
|
LOGFILE_ERROR,
|
||||||
service->name)));
|
"%s: Service not started due to lack of binlog directory %s",
|
||||||
free(inst);
|
service->name,
|
||||||
return NULL;
|
inst->binlogdir)));
|
||||||
}
|
|
||||||
LOGIF(LT, (skygw_log_write(
|
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,
|
LOGFILE_TRACE,
|
||||||
"Binlog router: current binlog file is: %s, current position %u\n",
|
"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
|
* We have completed the creation of the instance data, so now
|
||||||
@ -424,12 +560,15 @@ unsigned char *defuuid;
|
|||||||
sprintf(name, "%s stats", service->name);
|
sprintf(name, "%s stats", service->name);
|
||||||
hktask_add(name, stats_func, inst, BLR_STATS_FREQ);
|
hktask_add(name, stats_func, inst, BLR_STATS_FREQ);
|
||||||
}
|
}
|
||||||
|
free(name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now start the replication from the master to MaxScale
|
* Now start the replication from the master to MaxScale
|
||||||
*/
|
*/
|
||||||
blr_start_master(inst);
|
if (inst->master_state == BLRM_UNCONNECTED) {
|
||||||
free(name);
|
blr_start_master(inst);
|
||||||
|
}
|
||||||
|
|
||||||
return (ROUTER *)inst;
|
return (ROUTER *)inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +600,7 @@ ROUTER_SLAVE *slave;
|
|||||||
|
|
||||||
if ((slave = (ROUTER_SLAVE *)calloc(1, sizeof(ROUTER_SLAVE))) == NULL)
|
if ((slave = (ROUTER_SLAVE *)calloc(1, sizeof(ROUTER_SLAVE))) == NULL)
|
||||||
{
|
{
|
||||||
LOGIF(LD, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Insufficient memory to create new slave session for binlog router")));
|
"Insufficient memory to create new slave session for binlog router")));
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -732,9 +871,12 @@ struct tm tm;
|
|||||||
min10 /= 10.0;
|
min10 /= 10.0;
|
||||||
min5 /= 5.0;
|
min5 /= 5.0;
|
||||||
|
|
||||||
|
if (router_inst->master)
|
||||||
dcb_printf(dcb, "\tMaster connection DCB: %p\n",
|
dcb_printf(dcb, "\tMaster connection DCB: %p\n",
|
||||||
router_inst->master);
|
router_inst->master);
|
||||||
|
else
|
||||||
|
dcb_printf(dcb, "\tMaster connection DCB: 0x0\n");
|
||||||
|
|
||||||
dcb_printf(dcb, "\tMaster connection state: %s\n",
|
dcb_printf(dcb, "\tMaster connection state: %s\n",
|
||||||
blrm_states[router_inst->master_state]);
|
blrm_states[router_inst->master_state]);
|
||||||
|
|
||||||
@ -781,7 +923,7 @@ struct tm tm;
|
|||||||
dcb_printf(dcb, "\tNumber of residual data packets: %u\n",
|
dcb_printf(dcb, "\tNumber of residual data packets: %u\n",
|
||||||
router_inst->stats.n_residuals);
|
router_inst->stats.n_residuals);
|
||||||
dcb_printf(dcb, "\tAverage events per packet %.1f\n",
|
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",
|
dcb_printf(dcb, "\tLast event from master at: %s",
|
||||||
buf);
|
buf);
|
||||||
dcb_printf(dcb, "\t (%d seconds ago)\n",
|
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);
|
mysql_errno = (unsigned long) extract_field((uint8_t *)(GWBUF_DATA(message) + 5), 16);
|
||||||
errmsg = extract_message(message);
|
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) {
|
if (router->master_state < BLRM_BINLOGDUMP || router->master_state != BLRM_SLAVE_STOPPED) {
|
||||||
/* set mysql_errno */
|
/* set mysql_errno */
|
||||||
router->m_errno = mysql_errno;
|
router->m_errno = mysql_errno;
|
||||||
@ -1061,6 +1197,18 @@ unsigned long mysql_errno;
|
|||||||
if (router->m_errmsg)
|
if (router->m_errmsg)
|
||||||
free(router->m_errmsg);
|
free(router->m_errmsg);
|
||||||
router->m_errmsg = strdup(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)
|
if (errmsg)
|
||||||
@ -1070,7 +1218,7 @@ unsigned long mysql_errno;
|
|||||||
LOGFILE_MESSAGE,
|
LOGFILE_MESSAGE,
|
||||||
"%s: Master %s disconnected after %ld seconds. "
|
"%s: Master %s disconnected after %ld seconds. "
|
||||||
"%d events read.",
|
"%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)));
|
time(0) - router->connect_time, router->stats.n_binlogs_ses)));
|
||||||
blr_master_reconnect(router);
|
blr_master_reconnect(router);
|
||||||
}
|
}
|
||||||
@ -1308,3 +1456,234 @@ GWBUF *errbuf = NULL;
|
|||||||
|
|
||||||
return dcb->func.write(dcb, errbuf);
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -28,6 +28,8 @@
|
|||||||
* 08/06/2015 Massimiliano Pinto Addition of blr_cache_read_master_data()
|
* 08/06/2015 Massimiliano Pinto Addition of blr_cache_read_master_data()
|
||||||
* 15/06/2015 Massimiliano Pinto Addition of blr_file_get_next_binlogname()
|
* 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
|
* 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
|
* @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_get_next_binlogname(ROUTER_INSTANCE *router);
|
||||||
int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file);
|
int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file);
|
||||||
void blr_file_use_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
|
* Initialise the binlog file for this instance. MaxScale will look
|
||||||
@ -95,7 +98,7 @@ struct dirent *dp;
|
|||||||
strncat(path, router->service->name,PATH_MAX);
|
strncat(path, router->service->name,PATH_MAX);
|
||||||
|
|
||||||
if (access(path, R_OK) == -1)
|
if (access(path, R_OK) == -1)
|
||||||
mkdir(path, 0777);
|
mkdir(path, 0700);
|
||||||
|
|
||||||
router->binlogdir = strdup(path);
|
router->binlogdir = strdup(path);
|
||||||
}
|
}
|
||||||
@ -659,6 +662,8 @@ struct stat statb;
|
|||||||
* Write the response packet to a cache file so that MaxScale can respond
|
* Write the response packet to a cache file so that MaxScale can respond
|
||||||
* even if there is no master running when MaxScale starts.
|
* 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 router The instance of the router
|
||||||
* @param response The name of the response, used to name the cached file
|
* @param response The name of the response, used to name the cached file
|
||||||
* @param buf The buffer to written to the cache
|
* @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;
|
char path[4097], *ptr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
strcpy(path, "/usr/local/mariadb-maxscale");
|
strncpy(path, router->binlogdir, 4096);
|
||||||
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
strncat(path, "/cache", 4096);
|
||||||
{
|
|
||||||
strncpy(path, ptr, 4096);
|
if (access(path, R_OK) == -1) {
|
||||||
}
|
int mkdir_ret;
|
||||||
strncat(path, "/", 4096);
|
mkdir_ret = mkdir(path, 0700);
|
||||||
strncat(path, router->service->name, 4096);
|
}
|
||||||
|
|
||||||
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, "/", 4096);
|
||||||
strncat(path, response, 4096);
|
strncat(path, response, 4096);
|
||||||
|
|
||||||
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
|
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
|
||||||
return;
|
return;
|
||||||
write(fd, GWBUF_DATA(buf), GWBUF_LENGTH(buf));
|
write(fd, GWBUF_DATA(buf), GWBUF_LENGTH(buf));
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,6 +697,8 @@ int fd;
|
|||||||
* the router to start and serve any binlogs it already has on disk
|
* the router to start and serve any binlogs it already has on disk
|
||||||
* if the master is not available.
|
* if the master is not available.
|
||||||
*
|
*
|
||||||
|
* cache dir is 'cache' under router->binlogdir
|
||||||
|
*
|
||||||
* @param router The router instance structure
|
* @param router The router instance structure
|
||||||
* @param response The name of the response
|
* @param response The name of the response
|
||||||
* @return A pointer to a GWBUF structure
|
* @return A pointer to a GWBUF structure
|
||||||
@ -708,14 +711,9 @@ char path[4097], *ptr;
|
|||||||
int fd;
|
int fd;
|
||||||
GWBUF *buf;
|
GWBUF *buf;
|
||||||
|
|
||||||
strcpy(path, "/usr/local/mariadb-maxscale");
|
strncpy(path, router->binlogdir, 4096);
|
||||||
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
strncat(path, "/cache", 4096);
|
||||||
{
|
|
||||||
strncpy(path, ptr, 4096);
|
|
||||||
}
|
|
||||||
strncat(path, "/", 4096);
|
strncat(path, "/", 4096);
|
||||||
strncat(path, router->service->name, 4096);
|
|
||||||
strncat(path, "/.cache/", 4096);
|
|
||||||
strncat(path, response, 4096);
|
strncat(path, response, 4096);
|
||||||
|
|
||||||
if ((fd = open(path, O_RDONLY)) == -1)
|
if ((fd = open(path, O_RDONLY)) == -1)
|
||||||
@ -798,7 +796,9 @@ int filenum;
|
|||||||
|
|
||||||
if ((sptr = strrchr(router->binlog_name, '.')) == NULL)
|
if ((sptr = strrchr(router->binlog_name, '.')) == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
filenum = atoi(sptr+1) + 1;
|
filenum = atoi(sptr+1);
|
||||||
|
if (filenum)
|
||||||
|
filenum++;
|
||||||
|
|
||||||
return filenum;
|
return filenum;
|
||||||
}
|
}
|
||||||
@ -826,3 +826,73 @@ blr_file_use_binlog(ROUTER_INSTANCE *router, char *file)
|
|||||||
{
|
{
|
||||||
return blr_file_append(router, 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;
|
||||||
|
}
|
||||||
|
|||||||
@ -43,11 +43,14 @@
|
|||||||
* 15/06/2015 Massimiliano Pinto Added constraints to CHANGE MASTER TO MASTER_LOG_FILE/POS
|
* 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
|
* 23/06/2015 Massimiliano Pinto Added utility routines for blr_handle_change_master
|
||||||
* Call create/use binlog in blr_start_slave() (START SLAVE)
|
* 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
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <service.h>
|
#include <service.h>
|
||||||
#include <server.h>
|
#include <server.h>
|
||||||
@ -65,9 +68,12 @@
|
|||||||
#include <version.h>
|
#include <version.h>
|
||||||
#include <zlib.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_master_close(ROUTER_INSTANCE* router);
|
||||||
extern void blr_file_use_binlog(ROUTER_INSTANCE *router, char *file);
|
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_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);
|
int blr_file_get_next_binlogname(ROUTER_INSTANCE *router);
|
||||||
static uint32_t extract_field(uint8_t *src, int bits);
|
static uint32_t extract_field(uint8_t *src, int bits);
|
||||||
static void encode_value(unsigned char *data, unsigned int value, int len);
|
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_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_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_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 int lm_enabled_logfiles_bitmask;
|
||||||
extern size_t log_ses_count[];
|
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);
|
return blr_slave_query(router, slave, queue);
|
||||||
break;
|
break;
|
||||||
case COM_REGISTER_SLAVE:
|
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;
|
break;
|
||||||
case COM_BINLOG_DUMP:
|
case COM_BINLOG_DUMP:
|
||||||
return blr_slave_binlog_dump(router, slave, queue);
|
return blr_slave_binlog_dump(router, slave, queue);
|
||||||
@ -358,7 +380,13 @@ int query_len;
|
|||||||
else if (strcasecmp(word, "STATUS") == 0)
|
else if (strcasecmp(word, "STATUS") == 0)
|
||||||
{
|
{
|
||||||
free(query_text);
|
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)
|
else if (strcasecmp(word, "SLAVE") == 0)
|
||||||
@ -372,12 +400,20 @@ int query_len;
|
|||||||
else if (strcasecmp(word, "STATUS") == 0)
|
else if (strcasecmp(word, "STATUS") == 0)
|
||||||
{
|
{
|
||||||
free(query_text);
|
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)
|
else if (strcasecmp(word, "HOSTS") == 0)
|
||||||
{
|
{
|
||||||
free(query_text);
|
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);
|
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 */
|
/* start replication from the current configured master */
|
||||||
else if (strcasecmp(query_text, "START") == 0)
|
else if (strcasecmp(query_text, "START") == 0)
|
||||||
@ -451,7 +560,6 @@ int query_len;
|
|||||||
free(query_text);
|
free(query_text);
|
||||||
return blr_start_slave(router, slave);
|
return blr_start_slave(router, slave);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* stop replication from the current master*/
|
/* stop replication from the current master*/
|
||||||
else if (strcasecmp(query_text, "STOP") == 0)
|
else if (strcasecmp(query_text, "STOP") == 0)
|
||||||
@ -477,7 +585,7 @@ int query_len;
|
|||||||
}
|
}
|
||||||
else if (strcasecmp(word, "MASTER") == 0)
|
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);
|
free(query_text);
|
||||||
blr_slave_send_error_packet(slave, "Cannot change master with a running slave; run STOP SLAVE first", (unsigned int)1198, NULL);
|
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;
|
int rc;
|
||||||
char error_string[BINLOG_ERROR_MSG_LEN + 1] = "";
|
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);
|
rc = blr_handle_change_master(router, brkb, error_string);
|
||||||
|
|
||||||
free(query_text);
|
free(query_text);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
/* CHANGE MASTER TO has failed */
|
||||||
blr_slave_send_error_packet(slave, error_string, (unsigned int)1234, "42000");
|
blr_slave_send_error_packet(slave, error_string, (unsigned int)1234, "42000");
|
||||||
|
blr_master_free_config(current_master);
|
||||||
|
|
||||||
return 1;
|
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);
|
return blr_slave_send_ok(router, slave);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,8 +717,12 @@ blr_slave_replay(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *master)
|
|||||||
{
|
{
|
||||||
GWBUF *clone;
|
GWBUF *clone;
|
||||||
|
|
||||||
|
if (router->master_state == BLRM_UNCONFIGURED)
|
||||||
|
return blr_slave_send_ok(router, slave);
|
||||||
|
|
||||||
if (!master)
|
if (!master)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((clone = gwbuf_clone(master)) != NULL)
|
if ((clone = gwbuf_clone(master)) != NULL)
|
||||||
{
|
{
|
||||||
return slave->dcb->func.write(slave->dcb, clone);
|
return slave->dcb->func.write(slave->dcb, clone);
|
||||||
@ -2243,8 +2412,9 @@ uint8_t *ptr;
|
|||||||
/**
|
/**
|
||||||
* Stop current replication from master
|
* Stop current replication from master
|
||||||
*
|
*
|
||||||
* @param router The binlog router instance
|
* @param router The binlog router instance
|
||||||
* @param slave The slave server to which we are sending the response*
|
* @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;
|
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;
|
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 router The binlog router instance
|
||||||
* @param slave The slave server to which we are sending the response
|
* @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
|
static int
|
||||||
blr_start_slave(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave)
|
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);
|
/* if unconfigured return an error */
|
||||||
router->master_state = BLRM_UNCONNECTED;
|
if (router->master_state == BLRM_UNCONFIGURED) {
|
||||||
spinlock_release(&router->lock);
|
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;
|
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();
|
extern char *strcasestr();
|
||||||
char *option = NULL;
|
char *option = NULL;
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
|
char *new_ptr = NULL;
|
||||||
ptr = strcasestr(input, option_field);
|
ptr = strcasestr(input, option_field);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
char *end;
|
char *end;
|
||||||
@ -2412,9 +2629,11 @@ char *get_change_master_option(char *input, char *option_field) {
|
|||||||
end = strchr(option, ',');
|
end = strchr(option, ',');
|
||||||
if (end)
|
if (end)
|
||||||
*end = '\0';
|
*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);
|
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
|
* New binlog file could be the next one or current one
|
||||||
*/
|
*/
|
||||||
master_logfile = blr_set_master_logfile(router, command, error);
|
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 (master_logfile == NULL) {
|
||||||
/* if error return */
|
/* if errors return */
|
||||||
if (strlen(error)) {
|
if (strlen(error)) {
|
||||||
|
|
||||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, 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;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
/* binlog file not set by CHANGE MASTER, use current binlog */
|
/* If not set by CHANGE MASTER, use current binlog if configured */
|
||||||
master_logfile = strdup(router->binlog_name);
|
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) {
|
if (master_log_pos == NULL) {
|
||||||
pos = 0;
|
pos = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -2498,8 +2740,12 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
|
|||||||
pos = atoll(passed_pos);
|
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;
|
int return_error = 0;
|
||||||
if (master_log_pos == NULL) {
|
if (master_log_pos == NULL) {
|
||||||
snprintf(error, BINLOG_ERROR_MSG_LEN, "Please provide an explicit MASTER_LOG_POS for new MASTER_LOG_FILE %s: "
|
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;
|
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)
|
if (master_log_pos)
|
||||||
free(master_log_pos);
|
free(master_log_pos);
|
||||||
if (master_logfile)
|
if (master_logfile)
|
||||||
free(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 {
|
} 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: "
|
if (router->master_state == BLRM_UNCONFIGURED) {
|
||||||
"Permitted binlog pos is %lu. Current master_log_file=%s, master_log_pos=%lu",
|
if (pos && pos != 4) {
|
||||||
passed_pos,
|
snprintf(error, BINLOG_ERROR_MSG_LEN, "Can not set MASTER_LOG_POS to %s: "
|
||||||
router->binlog_position,
|
"Permitted binlog pos is 4. Specified master_log_file=%s",
|
||||||
router->binlog_name,
|
passed_pos,
|
||||||
router->binlog_position);
|
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)));
|
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, "%s: %s", router->service->name, error)));
|
||||||
|
|
||||||
if (master_log_pos)
|
if (master_log_pos)
|
||||||
@ -2582,7 +2849,24 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} 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)
|
if (master_log_pos)
|
||||||
free(master_log_pos);
|
free(master_log_pos);
|
||||||
if (master_logfile)
|
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 */
|
/* Change the replication user */
|
||||||
if (master_user) {
|
if (master_user) {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@ -2658,9 +2938,8 @@ int blr_handle_change_master(ROUTER_INSTANCE* router, char *command, char *error
|
|||||||
|
|
||||||
blr_master_free_config(current_master);
|
blr_master_free_config(current_master);
|
||||||
|
|
||||||
|
if (router->master_state == BLRM_UNCONFIGURED)
|
||||||
/* force stopped state */
|
change_binlog = 1;
|
||||||
router->master_state = BLRM_SLAVE_STOPPED;
|
|
||||||
|
|
||||||
spinlock_release(&router->lock);
|
spinlock_release(&router->lock);
|
||||||
|
|
||||||
@ -2748,24 +3027,24 @@ blr_set_master_port(ROUTER_INSTANCE *router, char *command) {
|
|||||||
* @param router Current router instance
|
* @param router Current router instance
|
||||||
* @param command CHANGE MASTER TO command
|
* @param command CHANGE MASTER TO command
|
||||||
* @param error The error msg for 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) {
|
char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error) {
|
||||||
int change_binlog = 0;
|
int change_binlog = 0;
|
||||||
char *new_binlog_file = NULL;
|
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 *ptr;
|
||||||
char *end;
|
char *end;
|
||||||
long next_binlog_seqname;
|
long next_binlog_seqname;
|
||||||
|
|
||||||
ptr = strchr(master_logfile, '\'');
|
ptr = strchr(logfile, '\'');
|
||||||
|
|
||||||
if (ptr)
|
if (ptr)
|
||||||
ptr++;
|
ptr++;
|
||||||
else
|
else
|
||||||
ptr = master_logfile + 16;
|
ptr = logfile + 16;
|
||||||
|
|
||||||
end = strchr(ptr+1, '\'');
|
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->service->name, ptr,
|
||||||
router->fileroot);
|
router->fileroot);
|
||||||
|
|
||||||
free(master_logfile);
|
free(logfile);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
end++;
|
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 */
|
/* get next binlog file name, assuming filestem is the same */
|
||||||
next_binlog_seqname = blr_file_get_next_binlogname(router);
|
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->service->name,
|
||||||
router->binlog_name);
|
router->binlog_name);
|
||||||
|
|
||||||
free(master_logfile);
|
free(logfile);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -2822,7 +3118,7 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
|
|||||||
router->binlog_name,
|
router->binlog_name,
|
||||||
router->binlog_position);
|
router->binlog_position);
|
||||||
|
|
||||||
free(master_logfile);
|
free(logfile);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -2834,7 +3130,7 @@ char *blr_set_master_logfile(ROUTER_INSTANCE *router, char *command, char *error
|
|||||||
/* allocate new filename */
|
/* allocate new filename */
|
||||||
new_binlog_file = strdup(ptr);
|
new_binlog_file = strdup(ptr);
|
||||||
|
|
||||||
free(master_logfile);
|
free(logfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_binlog_file;
|
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);
|
strncpy(curr_master->logfile, router->binlog_name, BINLOG_FNAMELEN);
|
||||||
curr_master->user = strdup(router->user);
|
curr_master->user = strdup(router->user);
|
||||||
curr_master->password = strdup(router->password);
|
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);
|
free(master_cfg->user);
|
||||||
if (master_cfg->password)
|
if (master_cfg->password)
|
||||||
free(master_cfg->password);
|
free(master_cfg->password);
|
||||||
|
if (master_cfg->filestem)
|
||||||
|
free(master_cfg->filestem);
|
||||||
|
|
||||||
free(master_cfg);
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user