Merge remote-tracking branch 'origin/develop' into MXS-122

Conflicts:
	server/core/dcb.c
This commit is contained in:
counterpoint
2015-07-08 14:54:22 +01:00
45 changed files with 1189 additions and 774 deletions

View File

@ -24,8 +24,9 @@
* @verbatim
* Revision History
*
* Date Who Description
* 02/04/14 Mark Riddoch Initial implementation
* Date Who Description
* 02/04/14 Mark Riddoch Initial implementation
* 11/05/15 Massimilaino Pinto Added mariadb10_compat to master and slave structs
*
* @endverbatim
*/
@ -176,6 +177,7 @@ typedef struct router_slave {
uint32_t lastEventTimestamp;/*< Last event timestamp sent */
SPINLOCK catch_lock; /*< Event catchup lock */
unsigned int cstate; /*< Catch up state */
bool mariadb10_compat;/*< MariaDB 10.0 compatibility */
SPINLOCK rses_lock; /*< Protects rses_deleted */
pthread_t pthread;
struct router_instance
@ -234,6 +236,7 @@ typedef struct {
GWBUF *selectvercom; /*< select @@version_comment */
GWBUF *selecthostname;/*< select @@hostname */
GWBUF *map; /*< select @@max_allowed_packet */
GWBUF *mariadb10; /*< set @mariadb_slave_capability */
uint8_t *fde_event; /*< Format Description Event */
int fde_len; /*< Length of fde_event */
} MASTER_RESPONSES;
@ -242,54 +245,54 @@ typedef struct {
* The per instance data for the router.
*/
typedef struct router_instance {
SERVICE *service; /*< Pointer to the service using this router */
ROUTER_SLAVE *slaves; /*< Link list of all the slave connections */
SPINLOCK lock; /*< Spinlock for the instance data */
char *uuid; /*< UUID for the router to use w/master */
int masterid; /*< Server ID of the master */
int serverid; /*< Server ID to use with master */
int initbinlog; /*< Initial binlog file number */
char *user; /*< User name to use with master */
char *password; /*< Password to use with master */
char *fileroot; /*< Root of binlog filename */
bool master_chksum;/*< Does the master provide checksums */
char *master_uuid; /*< UUID of the master */
DCB *master; /*< DCB for master connection */
DCB *client; /*< DCB for dummy client */
SESSION *session; /*< Fake session for master connection */
unsigned int master_state; /*< State of the master FSM */
uint8_t lastEventReceived;
uint32_t lastEventTimestamp; /*< Timestamp from last event */
GWBUF *residual; /*< Any residual binlog event */
MASTER_RESPONSES saved_master; /*< Saved master responses */
char *binlogdir; /*< The directory with the binlog files */
SPINLOCK binlog_lock; /*< Lock to control update of the binlog position */
char binlog_name[BINLOG_FNAMELEN+1];
SERVICE *service; /*< Pointer to the service using this router */
ROUTER_SLAVE *slaves; /*< Link list of all the slave connections */
SPINLOCK lock; /*< Spinlock for the instance data */
char *uuid; /*< UUID for the router to use w/master */
int masterid; /*< Server ID of the master */
int serverid; /*< Server ID to use with master */
int initbinlog; /*< Initial binlog file number */
char *user; /*< User name to use with master */
char *password; /*< Password to use with master */
char *fileroot; /*< Root of binlog filename */
bool master_chksum; /*< Does the master provide checksums */
bool mariadb10_compat; /*< MariaDB 10.0 compatibility */
char *master_uuid; /*< UUID of the master */
DCB *master; /*< DCB for master connection */
DCB *client; /*< DCB for dummy client */
SESSION *session; /*< Fake session for master connection */
unsigned int master_state; /*< State of the master FSM */
uint8_t lastEventReceived;
uint32_t lastEventTimestamp; /*< Timestamp from last event */
GWBUF *residual; /*< Any residual binlog event */
MASTER_RESPONSES saved_master; /*< Saved master responses */
char *binlogdir; /*< The directory with the binlog files */
SPINLOCK binlog_lock; /*< Lock to control update of the binlog position */
char binlog_name[BINLOG_FNAMELEN+1];
/*< Name of the current binlog file */
uint64_t binlog_position;
uint64_t binlog_position;
/*< Current binlog position */
int binlog_fd; /*< File descriptor of the binlog
int binlog_fd; /*< File descriptor of the binlog
* file being written
*/
uint64_t last_written; /*< Position of last event written */
char prevbinlog[BINLOG_FNAMELEN+1];
int rotating; /*< Rotation in progress flag */
BLFILE *files; /*< Files used by the slaves */
SPINLOCK fileslock; /*< Lock for the files queue above */
unsigned int low_water; /*< Low water mark for client DCB */
unsigned int high_water; /*< High water mark for client DCB */
unsigned int short_burst; /*< Short burst for slave catchup */
unsigned int long_burst; /*< Long burst for slave catchup */
unsigned long burst_size; /*< Maximum size of burst to send */
unsigned long heartbeat; /*< Configured heartbeat value */
ROUTER_STATS stats; /*< Statistics for this router */
int active_logs;
int reconnect_pending;
int retry_backoff;
time_t connect_time;
int handling_threads;
struct router_instance
*next;
uint64_t last_written; /*< Position of last event written */
char prevbinlog[BINLOG_FNAMELEN+1];
int rotating; /*< Rotation in progress flag */
BLFILE *files; /*< Files used by the slaves */
SPINLOCK fileslock; /*< Lock for the files queue above */
unsigned int low_water; /*< Low water mark for client DCB */
unsigned int high_water; /*< High water mark for client DCB */
unsigned int short_burst; /*< Short burst for slave catchup */
unsigned int long_burst; /*< Long burst for slave catchup */
unsigned long burst_size; /*< Maximum size of burst to send */
unsigned long heartbeat; /*< Configured heartbeat value */
ROUTER_STATS stats; /*< Statistics for this router */
int active_logs;
int reconnect_pending;
int retry_backoff;
time_t connect_time;
int handling_threads;
struct router_instance *next;
} ROUTER_INSTANCE;
/**
@ -315,15 +318,16 @@ typedef struct router_instance {
#define BLRM_MAP 0x0011
#define BLRM_REGISTER 0x0012
#define BLRM_BINLOGDUMP 0x0013
#define BLRM_MARIADB10 0x0014
#define BLRM_MAXSTATE 0x0013
#define BLRM_MAXSTATE 0x0014
static char *blrm_states[] = { "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",
"select version()", "select @@version_comment", "select @@hostname",
"select @@mx_allowed_packet", "Register slave", "Binlog Dump" };
"select @@mx_allowed_packet", "Register slave", "Binlog Dump", "Set MariaDB slave capability" };
#define BLRS_CREATED 0x0000
#define BLRS_UNREGISTERED 0x0001
@ -397,6 +401,7 @@ static char *blrs_states[] = { "Created", "Unregistered", "Registered",
#define PREVIOUS_GTIDS_EVENT 0x23
#define MAX_EVENT_TYPE 0x23
#define MAX_EVENT_TYPE_MARIADB10 0xa3
/**
* Binlog event flags

View File

@ -252,6 +252,7 @@ typedef struct rwsplit_config_st {
int rw_max_sescmd_history_size;
bool disable_sescmd_hist;
bool disable_slave_recovery;
bool master_reads; /*< Use master for reads */
} rwsplit_config_t;

View File

@ -245,4 +245,6 @@ typedef struct router_instance {
#define BACKEND_TYPE(b) (SERVER_IS_MASTER((b)->backend_server) ? BE_MASTER : \
(SERVER_IS_SLAVE((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED));
bool subsvc_is_valid(SUBSERVICE*);
#endif /*< _SHARDROUTER_H */

View File

@ -155,7 +155,10 @@ startMonitor(void *arg,void* opt)
else if(!strcmp(params->name,"script"))
{
if(handle->script)
{
free(handle->script);
handle->script = NULL;
}
if(access(params->value,X_OK) == 0)
{
@ -277,7 +280,7 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
{
GALERA_MONITOR* handle = (GALERA_MONITOR*)mon->handle;
MYSQL_ROW row;
MYSQL_RES *result;
MYSQL_RES *result,*result2;
int isjoined = 0;
char *uname = mon->user;
char *passwd = mon->password;
@ -369,6 +372,14 @@ char *server_string;
if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_state'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
if (strcmp(row[1], "4") == 0)
@ -377,13 +388,22 @@ char *server_string;
/* Check if the node is a donor and is using xtrabackup, in this case it can stay alive */
else if (strcmp(row[1], "2") == 0 && handle->availableWhenDonor == 1) {
if (mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
&& (result2 = mysql_store_result(database->con)) != NULL)
{
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
mysql_free_result(result2);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW VARIABLES LIKE 'wsrep_sst_method'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
if (strncmp(row[1], "xtrabackup", 10) == 0)
isjoined = 1;
}
mysql_free_result(result2);
}
}
}
@ -395,6 +415,15 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long local_index = -1;
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_index'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
local_index = strtol(row[1], NULL, 10);

View File

@ -366,7 +366,15 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
if(mysql_field_count(database->con) != 1)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for 'SELECT @@server_id'. Expected 1 column."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
server_id = strtol(row[0], NULL, 10);
@ -392,7 +400,16 @@ char *server_string;
{
int i = 0;
long master_id = -1;
if(mysql_field_count(database->con) < 42)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" "
"returned less than the expected amount of columns. Expected 42 columns"
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -431,7 +448,31 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long master_id = -1;
if(mysql_field_count(database->con) < 40)
{
mysql_free_result(result);
if(server_version < 5*10000 + 5*100)
{
if(database->log_version_err)
{
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
" for versions less than 5.5 does not have master_server_id, "
"replication tree cannot be resolved for server %s."
" MySQL Version: %s",database->server->unique_name,version_str);
database->log_version_err = false;
}
}
else
{
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
"returned less than the expected amount of columns. Expected 40 columns."
" MySQL Version: %s",version_str);
}
return;
}
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -463,6 +504,13 @@ char *server_string;
if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW GLOBAL VARIABLES LIKE 'read_only'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{

View File

@ -408,6 +408,13 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
if(mysql_field_count(database->con) != 1)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SELECT @@server_id\". Expected 1 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
server_id = strtol(row[0], NULL, 10);
@ -433,6 +440,16 @@ char *server_string;
{
int i = 0;
long master_id = -1;
if(mysql_field_count(database->con) < 42)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" "
"returned less than the expected amount of columns. Expected 42 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -471,6 +488,29 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long master_id = -1;
if(mysql_field_count(database->con) < 40)
{
mysql_free_result(result);
if(server_version < 5*10000 + 5*100)
{
if(database->log_version_err)
{
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
" for versions less than 5.5 does not have master_server_id, "
"replication tree cannot be resolved for server %s."
" MySQL Version: %s",database->server->unique_name,version_str);
database->log_version_err = false;
}
}
else
{
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
"returned less than the expected amount of columns. Expected 40 columns."
" MySQL Version: %s",version_str);
}
return;
}
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/

View File

@ -323,6 +323,14 @@ char *server_string;
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
while ((row = mysql_fetch_row(result)))
{
if (atoi(row[1]) > 0)
@ -335,6 +343,14 @@ char *server_string;
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_cluster_node_id'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if(mysql_field_count(database->con) < 2)
{
mysql_free_result(result);
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'Ndb_cluster_node_id'\". Expected 2 columns."
" MySQL Version: %s",version_str);
return;
}
long cluster_node_id = -1;
while ((row = mysql_fetch_row(result)))
{

View File

@ -58,6 +58,7 @@ extern __thread log_info_t tls_log_info;
* Revision History
* Date Who Description
* 13/06/2014 Mark Riddoch Initial implementation
* 07/07/15 Martin Brampton Correct failure handling
*
* @endverbatim
*/
@ -270,9 +271,7 @@ int n_connect = 0;
{
atomic_add(&dcb->stats.n_accepts, 1);
client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
if (client_dcb == NULL)
{
close(so);
return n_connect;
@ -283,7 +282,8 @@ int n_connect = 0;
if ((maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED))) == NULL)
{
client_dcb->protocol = NULL;
dcb_add_to_zombieslist(client_dcb);
close(so);
dcb_close(client_dcb);
return n_connect;
}
maxscaled_pr->username = NULL;
@ -293,9 +293,9 @@ int n_connect = 0;
client_dcb->session =
session_alloc(dcb->session->service, client_dcb);
if (poll_add_dcb(client_dcb) == -1)
if (poll_add_dcb(client_dcb))
{
dcb_add_to_zombieslist(dcb);
dcb_close(dcb);
return n_connect;
}
n_connect++;

View File

@ -1452,8 +1452,8 @@ int gw_MySQLListener(
// add listening socket to poll structure
if (poll_add_dcb(listen_dcb) == -1) {
fprintf(stderr,
"\n* Failed to start polling the socket due error "
"%i, %s.\n\n",
"\n* MaxScale encountered system limit while "
"attempting to register on an epoll instance.\n\n",
errno,
strerror(errno));
return 0;
@ -1688,7 +1688,8 @@ int gw_MySQLAccept(DCB *listener)
client_dcb,
1,
0,
"MaxScale internal error.");
"MaxScale encountered system limit while "
"attempting to register on an epoll instance.");
/** close client_dcb */
dcb_close(client_dcb);

View File

@ -36,6 +36,7 @@
* 03/10/2014 Massimiliano Pinto Added netmask for wildcard in IPv4 hosts.
* 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support
* 10/11/2014 Massimiliano Pinto Charset at connect is passed to backend during authentication
* 07/07/15 Martin Brampton Fix problem recognising null password
*
*/
@ -1550,13 +1551,6 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
break;
}
/** See if ANYDB == Y */
if(key.resource)
{
key.resource = NULL;
continue;
}
if (!user_password) {
/*
* user@% not found.

View File

@ -67,6 +67,7 @@ extern __thread log_info_t tls_log_info;
* Date Who Description
* 17/06/2013 Mark Riddoch Initial version
* 17/07/2013 Mark Riddoch Addition of login phase
* 07/07/2015 Martin Brampton Call unified dcb_close on error
*
* @endverbatim
*/
@ -315,13 +316,13 @@ int n_connect = 0;
if (telnetd_pr == NULL)
{
dcb_add_to_zombieslist(client_dcb);
dcb_close(client_dcb);
return n_connect;
}
if (poll_add_dcb(client_dcb) == -1)
if (poll_add_dcb(client_dcb))
{
dcb_add_to_zombieslist(dcb);
dcb_close(dcb);
return n_connect;
}
n_connect++;

View File

@ -35,6 +35,8 @@
* 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
* 07/05/2015 Massimiliano Pinto Addition of MariaDB 10 compatibility support
*
* @endverbatim
*/
@ -195,6 +197,7 @@ unsigned char *defuuid;
inst->retry_backoff = 1;
inst->binlogdir = NULL;
inst->heartbeat = 300; // Default is every 5 minutes
inst->mariadb10_compat = false;
inst->user = strdup(service->credentials.name);
inst->password = strdup(service->credentials.authdata);
@ -282,6 +285,10 @@ unsigned char *defuuid;
{
inst->masterid = atoi(value);
}
else if (strcmp(options[i], "mariadb10-compatibility") == 0)
{
inst->mariadb10_compat = config_truth_value(value);
}
else if (strcmp(options[i], "filestem") == 0)
{
inst->fileroot = strdup(value);
@ -388,6 +395,7 @@ unsigned char *defuuid;
inst->saved_master.selectvercom = blr_cache_read_response(inst, "selectvercom");
inst->saved_master.selecthostname = blr_cache_read_response(inst, "selecthostname");
inst->saved_master.map = blr_cache_read_response(inst, "map");
inst->saved_master.mariadb10 = blr_cache_read_response(inst, "mariadb10");
/*
* Initialise the binlog file and position
@ -490,6 +498,7 @@ ROUTER_SLAVE *slave;
strcpy(slave->binlogfile, "unassigned");
slave->connect_time = time(0);
slave->lastEventTimestamp = 0;
slave->mariadb10_compat = false;
/**
* Add this session to the list of active sessions.

View File

@ -23,8 +23,9 @@
* @verbatim
* Revision History
*
* Date Who Description
* Date Who Description
* 14/04/2014 Mark Riddoch Initial implementation
* 07/05/2015 Massimiliano Pinto Added MAX_EVENT_TYPE_MARIADB10
*
* @endverbatim
*/
@ -439,15 +440,26 @@ struct stat statb;
hdr->next_pos = EXTRACT32(&hdbuf[13]);
hdr->flags = EXTRACT16(&hdbuf[17]);
if (hdr->event_type > MAX_EVENT_TYPE)
{
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
"Invalid event type 0x%x. "
if (router->mariadb10_compat) {
if (hdr->event_type > MAX_EVENT_TYPE_MARIADB10) {
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
"Invalid MariaDB 10 event type 0x%x. "
"Binlog file is %s, position %d",
hdr->event_type,
file->binlogname, pos)));
return NULL;
}
return NULL;
}
} else {
if (hdr->event_type > MAX_EVENT_TYPE) {
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
"Invalid event type 0x%x. "
"Binlog file is %s, position %d",
hdr->event_type,
file->binlogname, pos)));
return NULL;
}
}
if (hdr->next_pos < pos && hdr->event_type != ROTATE_EVENT)
{

View File

@ -31,8 +31,9 @@
* @verbatim
* Revision History
*
* Date Who Description
* Date Who Description
* 02/04/2014 Mark Riddoch Initial implementation
* 07/05/2015 Massimiliano Pinto Added MariaDB 10 Compatibility
*
* @endverbatim
*/
@ -448,11 +449,27 @@ char query[128];
GWBUF_CONSUME_ALL(router->saved_master.chksum2);
router->saved_master.chksum2 = buf;
blr_cache_response(router, "chksum2", buf);
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
router->master_state = BLRM_GTIDMODE;
if (router->mariadb10_compat) {
buf = blr_make_query("SET @mariadb_slave_capability=4");
router->master_state = BLRM_MARIADB10;
} else {
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
router->master_state = BLRM_GTIDMODE;
}
router->master->func.write(router->master, buf);
break;
}
case BLRM_MARIADB10:
// Response to the SET @mariadb_slave_capability=4, should be stored
if (router->saved_master.mariadb10)
GWBUF_CONSUME_ALL(router->saved_master.mariadb10);
router->saved_master.mariadb10 = buf;
blr_cache_response(router, "mariadb10", buf);
buf = blr_make_query("SHOW VARIABLES LIKE 'SERVER_UUID'");
router->master_state = BLRM_MUUID;
router->master->func.write(router->master, buf);
break;
case BLRM_GTIDMODE:
// Response to the GTID_MODE, should be stored
if (router->saved_master.gtid_mode)

View File

@ -36,9 +36,12 @@
* 18/02/2015 Massimiliano Pinto Addition of DISCONNECT ALL and DISCONNECT SERVER server_id
* 18/03/2015 Markus Makela Better detection of CRC32 | NONE checksum
* 19/03/2015 Massimiliano Pinto Addition of basic MariaDB 10 compatibility support
* 07/05/2015 Massimiliano Pinto Added MariaDB 10 Compatibility
* 11/05/2015 Massimiliano Pinto Only MariaDB 10 Slaves can register to binlog router with a MariaDB 10 Master
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -123,7 +126,28 @@ 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 Master is MariaDB10 don't allow registration from
* MariaDB/Mysql 5 Slaves
*/
if (router->mariadb10_compat && !slave->mariadb10_compat) {
slave->state = BLRS_ERRORED;
blr_send_custom_error(slave->dcb, 1, 0,
"MariaDB 10 Slave is required for Slave registration");
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"%s: Slave %s: a MariaDB 10 Slave is required for Slave registration",
router->service->name,
slave->dcb->remote)));
dcb_close(slave->dcb);
return 1;
} else {
/* Master and Slave version OK: continue with slave registration */
return blr_slave_register(router, slave, queue);
}
break;
case COM_BINLOG_DUMP:
return blr_slave_binlog_dump(router, slave, queue);
@ -366,10 +390,17 @@ int query_len;
free(query_text);
return blr_slave_replay(router, slave, router->saved_master.heartbeat);
}
else if (strcasecmp(word, "@mariadb_slave_capability") == 0)
else if (strcasecmp(word, "@mariadb_slave_capability") == 0)
{
free(query_text);
return blr_slave_send_ok(router, slave);
/* mariadb10 compatibility is set for the slave */
slave->mariadb10_compat=true;
free(query_text);
if (router->mariadb10_compat) {
return blr_slave_replay(router, slave, router->saved_master.mariadb10);
} else {
return blr_slave_send_ok(router, slave);
}
}
else if (strcasecmp(word, "@master_binlog_checksum") == 0)
{
@ -442,7 +473,7 @@ int query_len;
query_text = strndup(qtext, query_len);
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR, "Unexpected query from slave server %s", query_text)));
LOGFILE_ERROR, "Unexpected query from slave %s: %s", slave->dcb->remote, query_text)));
free(query_text);
blr_slave_send_error(router, slave, "Unexpected SQL query received from slave.");
return 1;

View File

@ -113,14 +113,10 @@ MAXINFO_TREE *col, *table;
#endif
default:
*parse_error = PARSE_SYNTAX_ERROR;
if (tree)
free_tree(tree);
return NULL;
}
}
*parse_error = PARSE_SYNTAX_ERROR;
if (tree)
free_tree(tree);
return NULL;
}

View File

@ -226,7 +226,7 @@ static rses_property_t* mysql_sescmd_get_property(
static rses_property_t* rses_property_init(
rses_property_type_t prop_type);
static void rses_property_add(
static int rses_property_add(
ROUTER_CLIENT_SES* rses,
rses_property_t* prop);
@ -287,7 +287,7 @@ static sescmd_cursor_t* backend_ref_get_sescmd_cursor (backend_ref_t* bref);
static int router_handle_state_switch(DCB* dcb, DCB_REASON reason, void* data);
static bool handle_error_new_connection(
ROUTER_INSTANCE* inst,
ROUTER_CLIENT_SES* rses,
ROUTER_CLIENT_SES** rses,
DCB* backend_dcb,
GWBUF* errmsg);
static void handle_error_reply_client(
@ -1243,7 +1243,8 @@ static bool get_dcb(
SERVER_IS_SLAVE(b->backend_server) &&
(max_rlag == MAX_RLAG_UNDEFINED ||
(b->backend_server->rlag != MAX_RLAG_NOT_AVAILABLE &&
b->backend_server->rlag <= max_rlag)))
b->backend_server->rlag <= max_rlag)) &&
!rses->rses_config.master_reads)
{
/** found slave */
candidate_bref = &backend_ref[i];
@ -2941,6 +2942,11 @@ static void bref_clear_state(
backend_ref_t* bref,
bref_state_t state)
{
if(bref == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to bref_clear_state. (%s:%d)",__FILE__,__LINE__);
return;
}
if (state != BREF_WAITING_RESULT)
{
bref->bref_state &= ~state;
@ -2970,6 +2976,11 @@ static void bref_set_state(
backend_ref_t* bref,
bref_state_t state)
{
if(bref == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to bref_set_state. (%s:%d)",__FILE__,__LINE__);
return;
}
if (state != BREF_WAITING_RESULT)
{
bref->bref_state |= state;
@ -3533,7 +3544,8 @@ static rses_property_t* rses_property_init(
prop = (rses_property_t*)calloc(1, sizeof(rses_property_t));
if (prop == NULL)
{
goto return_prop;
skygw_log_write(LE,"Error: Malloc returned NULL. (%s:%d)",__FILE__,__LINE__);
return NULL;
}
prop->rses_prop_type = prop_type;
#if defined(SS_DEBUG)
@ -3541,7 +3553,6 @@ static rses_property_t* rses_property_init(
prop->rses_prop_chk_tail = CHK_NUM_ROUTER_PROPERTY;
#endif
return_prop:
CHK_RSES_PROP(prop);
return prop;
}
@ -3552,6 +3563,11 @@ return_prop:
static void rses_property_done(
rses_property_t* prop)
{
if(prop == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to rses_property_done. (%s:%d)",__FILE__,__LINE__);
return;
}
CHK_RSES_PROP(prop);
switch (prop->rses_prop_type) {
@ -3585,10 +3601,20 @@ static void rses_property_done(
*
* Router client session must be locked.
*/
static void rses_property_add(
static int rses_property_add(
ROUTER_CLIENT_SES* rses,
rses_property_t* prop)
{
if(rses == NULL)
{
skygw_log_write(LE,"Error: Router client session is NULL. (%s:%d)",__FILE__,__LINE__);
return -1;
}
if(prop == NULL)
{
skygw_log_write(LE,"Error: Router client session property is NULL. (%s:%d)",__FILE__,__LINE__);
return -1;
}
rses_property_t* p;
CHK_CLIENT_RSES(rses);
@ -3610,6 +3636,7 @@ static void rses_property_add(
}
p->rses_prop_next = prop;
}
return 0;
}
/**
@ -3620,7 +3647,13 @@ static mysql_sescmd_t* rses_property_get_sescmd(
rses_property_t* prop)
{
mysql_sescmd_t* sescmd;
if(prop == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to rses_property_get_sescmd. (%s:%d)",__FILE__,__LINE__);
return NULL;
}
CHK_RSES_PROP(prop);
ss_dassert(prop->rses_prop_rsession == NULL ||
SPINLOCK_IS_LOCKED(&prop->rses_prop_rsession->rses_lock));
@ -3633,22 +3666,6 @@ static mysql_sescmd_t* rses_property_get_sescmd(
}
return sescmd;
}
/**
static void rses_begin_locked_property_action(
rses_property_t* prop)
{
CHK_RSES_PROP(prop);
spinlock_acquire(&prop->rses_prop_lock);
}
static void rses_end_locked_property_action(
rses_property_t* prop)
{
CHK_RSES_PROP(prop);
spinlock_release(&prop->rses_prop_lock);
}
*/
/**
* Create session command property.
@ -3681,6 +3698,11 @@ static mysql_sescmd_t* mysql_sescmd_init (
static void mysql_sescmd_done(
mysql_sescmd_t* sescmd)
{
if(sescmd == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to mysql_sescmd_done. (%s:%d)",__FILE__,__LINE__);
return;
}
CHK_RSES_PROP(sescmd->my_sescmd_prop);
gwbuf_free(sescmd->my_sescmd_buf);
memset(sescmd, 0, sizeof(mysql_sescmd_t));
@ -3763,7 +3785,7 @@ static GWBUF* sescmd_cursor_process_replies(
dcb_close(bref->bref_dcb);
*reconnect = true;
if(replybuf)
gwbuf_consume(replybuf,gwbuf_length(replybuf));
while((replybuf = gwbuf_consume(replybuf,gwbuf_length(replybuf))));
}
}
/** This is a response from the master and it is the "right" one.
@ -3806,7 +3828,7 @@ static GWBUF* sescmd_cursor_process_replies(
skygw_log_write(LOGFILE_DEBUG,"Slave '%s' responded faster to a session command.",
bref->bref_backend->backend_server->unique_name);
if(replybuf)
gwbuf_free(replybuf);
while((replybuf = gwbuf_consume(replybuf,gwbuf_length(replybuf))));
return NULL;
}
@ -3853,6 +3875,12 @@ static bool sescmd_cursor_is_active(
sescmd_cursor_t* sescmd_cursor)
{
bool succp;
if(sescmd_cursor == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_is_active. (%s:%d)",__FILE__,__LINE__);
return false;
}
ss_dassert(SPINLOCK_IS_LOCKED(&sescmd_cursor->scmd_cur_rses->rses_lock));
succp = sescmd_cursor->scmd_cur_active;
@ -3878,6 +3906,11 @@ static GWBUF* sescmd_cursor_clone_querybuf(
sescmd_cursor_t* scur)
{
GWBUF* buf;
if(scur == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_clone_querybuf. (%s:%d)",__FILE__,__LINE__);
return NULL;
}
ss_dassert(scur->scmd_cur_cmd != NULL);
buf = gwbuf_clone(scur->scmd_cur_cmd->my_sescmd_buf);
@ -3890,7 +3923,12 @@ static bool sescmd_cursor_history_empty(
sescmd_cursor_t* scur)
{
bool succp;
if(scur == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_history_empty. (%s:%d)",__FILE__,__LINE__);
return true;
}
CHK_SESCMD_CUR(scur);
if (scur->scmd_cur_rses->rses_properties[RSES_PROP_TYPE_SESCMD] == NULL)
@ -3910,6 +3948,11 @@ static void sescmd_cursor_reset(
sescmd_cursor_t* scur)
{
ROUTER_CLIENT_SES* rses;
if(scur == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_reset. (%s:%d)",__FILE__,__LINE__);
return;
}
CHK_SESCMD_CUR(scur);
CHK_CLIENT_RSES(scur->scmd_cur_rses);
rses = scur->scmd_cur_rses;
@ -3926,6 +3969,11 @@ static bool execute_sescmd_history(
{
bool succp;
sescmd_cursor_t* scur;
if(bref == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to execute_sescmd_history. (%s:%d)",__FILE__,__LINE__);
return false;
}
CHK_BACKEND_REF(bref);
scur = &bref->bref_sescmd_cur;
@ -3961,7 +4009,12 @@ static bool execute_sescmd_in_backend(
bool succp;
int rc = 0;
sescmd_cursor_t* scur;
GWBUF* buf;
if(backend_ref == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to execute_sescmd_in_backend. (%s:%d)",__FILE__,__LINE__);
return false;
}
if (BREF_IS_CLOSED(backend_ref))
{
succp = false;
@ -3993,27 +4046,9 @@ static bool execute_sescmd_in_backend(
/** Cursor is left active when function returns. */
sescmd_cursor_set_active(scur, true);
}
#if defined(SS_DEBUG)
LOGIF(LT, tracelog_routed_query(scur->scmd_cur_rses,
"execute_sescmd_in_backend",
backend_ref,
sescmd_cursor_clone_querybuf(scur)));
{
GWBUF* tmpbuf = sescmd_cursor_clone_querybuf(scur);
uint8_t* ptr = GWBUF_DATA(tmpbuf);
unsigned char cmd = MYSQL_GET_COMMAND(ptr);
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [execute_sescmd_in_backend] Just before write, fd "
"%d : cmd %s.",
pthread_self(),
dcb->fd,
STRPACKETTYPE(cmd))));
gwbuf_free(tmpbuf);
}
#endif /*< SS_DEBUG */
buf = sescmd_cursor_clone_querybuf(scur);
switch (scur->scmd_cur_cmd->my_sescmd_packet_type) {
case MYSQL_COM_CHANGE_USER:
/** This makes it possible to handle replies correctly */
@ -4022,7 +4057,7 @@ static bool execute_sescmd_in_backend(
dcb,
NULL,
dcb->session,
sescmd_cursor_clone_querybuf(scur));
buf);
break;
case MYSQL_COM_INIT_DB:
@ -4048,10 +4083,11 @@ static bool execute_sescmd_in_backend(
* Mark session command buffer, it triggers writing
* MySQL command to protocol
*/
gwbuf_set_type(scur->scmd_cur_cmd->my_sescmd_buf, GWBUF_TYPE_SESCMD);
rc = dcb->func.write(
dcb,
sescmd_cursor_clone_querybuf(scur));
buf);
break;
}
@ -4061,6 +4097,7 @@ static bool execute_sescmd_in_backend(
}
else
{
while((buf = GWBUF_CONSUME_ALL(buf)) != NULL);
succp = false;
}
return_succp:
@ -4082,6 +4119,12 @@ static bool sescmd_cursor_next(
rses_property_t* prop_curr;
rses_property_t* prop_next;
if(scur == NULL)
{
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_next. (%s:%d)",__FILE__,__LINE__);
return false;
}
ss_dassert(scur != NULL);
ss_dassert(*(scur->scmd_cur_ptr_property) != NULL);
ss_dassert(SPINLOCK_IS_LOCKED(
@ -4408,11 +4451,21 @@ static bool route_session_write(
* prevent it from being released before properties
* are cleaned up as a part of router sessionclean-up.
*/
prop = rses_property_init(RSES_PROP_TYPE_SESCMD);
if((prop = rses_property_init(RSES_PROP_TYPE_SESCMD)) == NULL)
{
skygw_log_write(LE,"Error: Router session property initialization failed");
rses_end_locked_router_action(router_cli_ses);
return false;
}
mysql_sescmd_init(prop, querybuf, packet_type, router_cli_ses);
/** Add sescmd property to router client session */
rses_property_add(router_cli_ses, prop);
if(rses_property_add(router_cli_ses, prop) != 0)
{
skygw_log_write(LE,"Error: Session property addition failed.");
rses_end_locked_router_action(router_cli_ses);
return false;
}
for (i=0; i<router_cli_ses->rses_nbackends; i++)
{
@ -4535,7 +4588,10 @@ static void rwsplit_process_router_options(
int i;
char* value;
select_criteria_t c;
if(options == NULL)
return;
for (i = 0; options[i]; i++)
{
if ((value = strchr(options[i], '=')) == NULL)
@ -4588,6 +4644,10 @@ static void rwsplit_process_router_options(
{
router->rwsplit_config.disable_slave_recovery = config_truth_value(value);
}
else if(strcmp(options[i],"master_accept_reads") == 0)
{
router->rwsplit_config.master_reads = config_truth_value(value);
}
}
} /*< for */
}
@ -4619,7 +4679,7 @@ static void handleError (
SESSION* session;
ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES *)router_session;
CHK_DCB(backend_dcb);
/** Reset error handle flag from a given DCB */
@ -4686,14 +4746,15 @@ static void handleError (
{
/**
* This is called in hope of getting replacement for
* failed slave(s).
* failed slave(s). This call may free rses.
*/
*succp = handle_error_new_connection(inst,
rses,
&rses,
backend_dcb,
errmsgbuf);
}
rses_end_locked_router_action(rses);
/* Free the lock if rses still exists */
if (rses) rses_end_locked_router_action(rses);
break;
}
@ -4762,10 +4823,11 @@ static void handle_error_reply_client(
*/
static bool handle_error_new_connection(
ROUTER_INSTANCE* inst,
ROUTER_CLIENT_SES* rses,
ROUTER_CLIENT_SES** rses,
DCB* backend_dcb,
GWBUF* errmsg)
{
ROUTER_CLIENT_SES* myrses;
SESSION* ses;
int router_nservers;
int max_nslaves;
@ -4773,7 +4835,8 @@ static bool handle_error_new_connection(
backend_ref_t* bref;
bool succp;
ss_dassert(SPINLOCK_IS_LOCKED(&rses->rses_lock));
myrses = *rses;
ss_dassert(SPINLOCK_IS_LOCKED(&myrses->rses_lock));
ses = backend_dcb->session;
CHK_SESSION(ses);
@ -4781,7 +4844,7 @@ static bool handle_error_new_connection(
/**
* If bref == NULL it has been replaced already with another one.
*/
if ((bref = get_bref_from_dcb(rses, backend_dcb)) == NULL)
if ((bref = get_bref_from_dcb(myrses, backend_dcb)) == NULL)
{
succp = true;
goto return_succp;
@ -4824,25 +4887,25 @@ static bool handle_error_new_connection(
(void *)bref);
router_nservers = router_get_servercount(inst);
max_nslaves = rses_get_max_slavecount(rses, router_nservers);
max_slave_rlag = rses_get_max_replication_lag(rses);
max_nslaves = rses_get_max_slavecount(myrses, router_nservers);
max_slave_rlag = rses_get_max_replication_lag(myrses);
/**
* Try to get replacement slave or at least the minimum
* number of slave connections for router session.
*/
if(inst->rwsplit_config.disable_slave_recovery)
{
succp = have_enough_servers(&rses,1,router_nservers,inst) ? true : false;
succp = have_enough_servers(&myrses,1,router_nservers,inst) ? true : false;
}
else
{
succp = select_connect_backend_servers(
&rses->rses_master_ref,
rses->rses_backend_ref,
&myrses->rses_master_ref,
myrses->rses_backend_ref,
router_nservers,
max_nslaves,
max_slave_rlag,
rses->rses_config.rw_slave_select_criteria,
myrses->rses_config.rw_slave_select_criteria,
ses,
inst);
}
@ -5079,10 +5142,9 @@ static int router_handle_state_switch(
{
backend_ref_t* bref;
int rc = 1;
ROUTER_CLIENT_SES* rses;
SESSION* ses;
SERVER* srv;
ROUTER_CLIENT_SES* rses;
SESSION* ses;
CHK_DCB(dcb);
bref = (backend_ref_t *)data;
CHK_BACKEND_REF(bref);
@ -5103,8 +5165,7 @@ static int router_handle_state_switch(
STRSRVSTATUS(srv))));
ses = dcb->session;
CHK_SESSION(ses);
rses = (ROUTER_CLIENT_SES *)dcb->session->router_session;
rses = (ROUTER_CLIENT_SES *)dcb->session->router_session;
CHK_CLIENT_RSES(rses);
switch (reason) {

View File

@ -46,7 +46,7 @@ bool extract_database(GWBUF* buf, char* str)
tok = strtok_r(query," ;",&saved);
if(tok == NULL || strcasecmp(tok,"use") != 0)
{
skygw_log_write(LOGFILE_ERROR,"Schemarouter: Malformed chage database packet.");
skygw_log_write(LOGFILE_ERROR,"extract_database: Malformed chage database packet.");
succp = false;
goto retblock;
}
@ -54,7 +54,7 @@ bool extract_database(GWBUF* buf, char* str)
tok = strtok_r(NULL," ;",&saved);
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR,"Schemarouter: Malformed chage database packet.");
skygw_log_write(LOGFILE_ERROR,"extract_database: Malformed chage database packet.");
succp = false;
goto retblock;
}

View File

@ -319,7 +319,7 @@ parse_mapping_response(ROUTER_CLIENT_SES* rses, char* target, GWBUF* buf)
if(PTR_IS_RESULTSET(((unsigned char*)buf->start)) &&
modutil_count_signal_packets(buf,0,0,&more) == 2)
{
ptr = (char*)buf->start;
ptr = (unsigned char*)buf->start;
if(ptr[5] != 1)
{