Merge branch 'origin/develop'
This commit is contained in:
@ -41,6 +41,11 @@
|
|||||||
- [Tee Filter](filters/Tee-Filter.md)
|
- [Tee Filter](filters/Tee-Filter.md)
|
||||||
- [Top N Filter](filters/Top-N-Filter.md)
|
- [Top N Filter](filters/Top-N-Filter.md)
|
||||||
- [Firewall Filter](filters/Firewall-Filter.md)
|
- [Firewall Filter](filters/Firewall-Filter.md)
|
||||||
|
- [RabbitMQ Filter](filters/RabbitMQ-Filter.md)
|
||||||
|
|
||||||
|
## Utilities
|
||||||
|
|
||||||
|
- [RabbitMQ Consumer Client](filters/RabbitMQ-Consumer-Client.md)
|
||||||
|
|
||||||
## Design Documents
|
## Design Documents
|
||||||
|
|
||||||
@ -55,3 +60,4 @@
|
|||||||
- [MaxScale 1.0 Release Notes](Release-Notes/MaxScale-1.0-Release-Notes.md)
|
- [MaxScale 1.0 Release Notes](Release-Notes/MaxScale-1.0-Release-Notes.md)
|
||||||
- [MaxScale 1.0.1 Release Notes](Release-Notes/MaxScale-1.0.1-Release-Notes.md)
|
- [MaxScale 1.0.1 Release Notes](Release-Notes/MaxScale-1.0.1-Release-Notes.md)
|
||||||
- [MaxScale 1.0.3 Release Notes](Release-Notes/MaxScale-1.0.3-Release-Notes.md)
|
- [MaxScale 1.0.3 Release Notes](Release-Notes/MaxScale-1.0.3-Release-Notes.md)
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -59,11 +59,16 @@ As with uuid, MaxScale must have a unique server-id for the connection it makes
|
|||||||
|
|
||||||
### user
|
### user
|
||||||
|
|
||||||
This is the user name that MaxScale uses when it connects to the master. This user name must have the rights required for replication as with any other user that a slave uses for replication purposes.
|
This is the user name that MaxScale uses when it connects to the master. This user name must have the rights required for replication as with any other user that a slave uses for replication purposes. If the user parameter is not given in the router options then the same user as is used to retrieve the credential information will be used for the replication connection, i.e. the user in the service entry.
|
||||||
|
|
||||||
|
The user that is used for replication, either defined using the user= option in the router options or using the username and password defined of the service must be granted replication privileges on the database server.
|
||||||
|
|
||||||
|
MariaDB> CREATE USER 'repl'@'maxscalehost' IDENTIFIED by 'password';
|
||||||
|
MariaDB> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'maxscalehost';
|
||||||
|
|
||||||
### password
|
### password
|
||||||
|
|
||||||
The password of the above user.
|
The password of the above user. If the password is not explicitly given then the password in the service entry will be used. For compatibility with other username and password definitions within the MaxScale configuration file it is also possible to use the parameter passwd=.
|
||||||
|
|
||||||
### master-id
|
### master-id
|
||||||
|
|
||||||
@ -75,7 +80,7 @@ This parameter is used to provide the stem of the file names that are used to st
|
|||||||
|
|
||||||
### initialfile
|
### initialfile
|
||||||
|
|
||||||
This optional parameter allows for the administrator to define the number of the first binlog file to download. In normal circumstances MaxScale will use any existing binlog file to determine what to request from the master. If there are no files it will then ask for the binlog file with the index number defined in the initialfile parameter. If this parameter is not set then MaxScale will ask the master for binlog events from file 1.
|
This optional parameter allows for the administrator to define the number of the first binlog file to download. If MaxScale has previously received binlogs it will use those existing binlog files to determine what to request from the master. If no files have been downloaded MaxScale will then ask for the binlog file with the index number defined in the initialfile parameter. If this parameter is not set then MaxScale will ask the master for binlog events from file 1.
|
||||||
|
|
||||||
### binlogdir
|
### binlogdir
|
||||||
|
|
||||||
@ -87,19 +92,21 @@ This defines the value of the heartbeat interval in seconds for the connection t
|
|||||||
|
|
||||||
### burstsize
|
### burstsize
|
||||||
|
|
||||||
This parameter is used to define the maximum amount of data that will be sent to a slave by MaxScale when that slave is lagging behind the master. In this situation the slave is said to be in "catchup mode", this parameter is designed to both prevent flooding of that slave and also to prevent threads within MaxScale spending disproportionate amounts of time with slaves that are lagging behind the master. The burst size can be defined in Kb, Mb or Gb by adding the qualifier K, M or G to the number given.
|
This parameter is used to define the maximum amount of data that will be sent to a slave by MaxScale when that slave is lagging behind the master. In this situation the slave is said to be in "catchup mode", this parameter is designed to both prevent flooding of that slave and also to prevent threads within MaxScale spending disproportionate amounts of time with slaves that are lagging behind the master. The burst size can be defined in Kb, Mb or Gb by adding the qualifier K, M or G to the number given. The default value of burstsize is 1Mb and will be used if burstsize is not given in the router options.
|
||||||
|
|
||||||
A complete example of a service entry for a binlog router service would be as follows.
|
A complete example of a service entry for a binlog router service would be as follows.
|
||||||
|
|
||||||
[Replication]
|
[Replication]
|
||||||
type=service
|
type=service
|
||||||
router=binlogrouter
|
router=binlogrouter
|
||||||
servers=maserdb
|
servers=masterdb
|
||||||
version_string=5.6.17-log
|
version_string=5.6.17-log
|
||||||
router_options=uuid=f12fcb7f-b97b-11e3-bc5e-0401152c4c22,server-id=3,user=repl,password=slavepass,master-id=1,filestem=mybin,heartbeat=30,binlogdir=/home/mriddoch/binlogs
|
router_options=uuid=f12fcb7f-b97b-11e3-bc5e-0401152c4c22,server-id=3,user=repl,password=slavepass,master-id=1,filestem=mybin,heartbeat=30,binlogdir=/home/mriddoch/binlogs
|
||||||
user=maxscale
|
user=maxscale
|
||||||
passwd=Mhu87p2D
|
passwd=Mhu87p2D
|
||||||
|
|
||||||
|
The minimum set of router options that must be given in the configuration are are server-id and aster-id, default values may be used for all other options.
|
||||||
|
|
||||||
## Listener Section
|
## Listener Section
|
||||||
|
|
||||||
As per any service in MaxScale a listener section is required to define the address, port and protocol that is used to listen for incoming connections. In this case those incoming connections will originate from the slave servers.
|
As per any service in MaxScale a listener section is required to define the address, port and protocol that is used to listen for incoming connections. In this case those incoming connections will originate from the slave servers.
|
||||||
|
38
Documentation/filters/RabbitMQ-Consumer-Client.md
Normal file
38
Documentation/filters/RabbitMQ-Consumer-Client.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#RabbitMQ Consumer Client
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This utility tool is used to read messages from a RabbitMQ broker sent by the [RabbitMQ Filter](RabbitMQ-Filter.md) and forward these messages into an SQL database as queries.
|
||||||
|
|
||||||
|
## Command Line Arguments
|
||||||
|
|
||||||
|
The **RabbitMQ Consumer Client** only has one command line argument.
|
||||||
|
|
||||||
|
| Command | Argument |
|
||||||
|
|---------|-------------------------------------------------|
|
||||||
|
| -c | Path to the folder containing the configuration file |
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install the RabbitMQ Consumer Client you ca either use the provided packages or you can compile it from source code. The source code is included as a part of the MaxScale source code and can be found in the `rabbtmq_consumer` folder. Please refer to the [README](../../rabbitmq_consumer/README) in the folder for more detailed instructions about installation and configuration.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The consumer client requires that the `consumer.cnf` configuration file is either be present in the `etc` folder of the installation directory or in the folder specified by the `-c` argument.
|
||||||
|
|
||||||
|
The source broker, the destination database and the message log file can be configured into the separate `consumer.cnf` file.
|
||||||
|
|
||||||
|
| Option | Desctiption |
|
||||||
|
|-----------|---------------------------------------------|
|
||||||
|
| hostname | Hostname of the RabbitMQ server |
|
||||||
|
| port | Port of the RabbitMQ server |
|
||||||
|
| vhost | Virtual host location of the RabbitMQ server |
|
||||||
|
| user | Username for the RabbitMQ server |
|
||||||
|
| passwd | Password for the RabbitMQ server |
|
||||||
|
| queue | Queue to consume from |
|
||||||
|
| dbserver | Hostname of the SQL server |
|
||||||
|
| dbport | Port of the SQL server |
|
||||||
|
| dbname | Name of the SQL database to use |
|
||||||
|
| dbuser | Database username |
|
||||||
|
| dbpasswd | Database passwork |
|
||||||
|
| logfile | Message log filename |
|
61
Documentation/filters/RabbitMQ-Filter.md
Normal file
61
Documentation/filters/RabbitMQ-Filter.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#RabbitMQ Filter
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This filter is designed to extract queries and transform them into a canonical form e.g. `INSERT INTO dabata.table VALUES ("John Doe", "Downtown",100,50.0);` turns into `INSERT INTO dabata.table VALUES ("?", "?",?,?);`. The filter pushes these canonized queries and their replies in to a RabbitMQ broker where they can later be retrieved. The retrieval can be done with your own application or the [RabbitMQ Consumer Client](RabbitMQ-Consumer-Client.md) utility tool, which reads the messages from the broker and sends the contents of those messages as SQL queries to a database.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The configuration block for the **mqfilter** filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf. Although the filter will start, it will use the default values which only work with a freshly installed RabbitMQ server and use its default values. This setup is mostly intednded for testing the filter.
|
||||||
|
|
||||||
|
The following is an example of a mqfilter configuration in the MaxScale.cnf file used for actual logging of queries to a RabbitMQ broker on a different host.
|
||||||
|
|
||||||
|
```
|
||||||
|
[RabbitMQ]
|
||||||
|
type=filter
|
||||||
|
module=mqfilter
|
||||||
|
hostname=192.168.122.100
|
||||||
|
port=4000
|
||||||
|
username=messageuser
|
||||||
|
password=msgpwd
|
||||||
|
exchange=msg-ex-1
|
||||||
|
key=MaxScale
|
||||||
|
logging_trigger=object,schema,source
|
||||||
|
logging_strict=false
|
||||||
|
logging_log_all=false
|
||||||
|
logging_object=my1
|
||||||
|
logging_schema=test
|
||||||
|
logging_source_user=maxtest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filter Options
|
||||||
|
|
||||||
|
The mqfilter filter does not support any filter options.
|
||||||
|
|
||||||
|
### Filter Parameters
|
||||||
|
|
||||||
|
The RabbitMQ filter has parameters to control which queries are logged based on either the attributes of the user or the query itself. These can be combined to to only log queries targeting a certain table in a certain database from a certain user from a certain network address.
|
||||||
|
|
||||||
|
|
||||||
|
Option | Description | Accepted Values | Default |
|
||||||
|
--------|-------------|-----------------|-------------
|
||||||
|
logging_trigger | Set the logging level | `all, source, schema, object` | `all` |
|
||||||
|
logging_strict | Sets whether to trigger when any of the parameters match or only if all parameters match | `true, false` | `false` |
|
||||||
|
logging_log_all | Log only SELECT, UPDATE, DELETE and INSERT or all possible queries | `true, false` | `true` |
|
||||||
|
logging_source_user | Comma-separated list of usernames to log | | |
|
||||||
|
logging_source_host | Comma-separated list of hostnames to log | | |
|
||||||
|
logging_schema | Comma-separated list of databases | | |
|
||||||
|
logging_object | Comma-separated list of database objects |
|
||||||
|
hostname | The server hostname where the messages are sent | | `localhost` |
|
||||||
|
port | Port to send the messages to | | `5672` |
|
||||||
|
username | Server login username | | `guest` |
|
||||||
|
password | Server login password | | `guest` |
|
||||||
|
vhost | The virtual host location on the server, where the messages are sent | | `/` |
|
||||||
|
exchange | The name of the exchange | | `default_exchange` |
|
||||||
|
exchange_type | The type of the exchange | `direct, fanout, topic, headers` | `direct` |
|
||||||
|
key | The routing key used when sending messages to the exchange | | `key` |
|
||||||
|
queue | The queue that will be bound to the used exchange | | |
|
||||||
|
ssl_CA_cert | Path to the CA certificate in PEM format | | |
|
||||||
|
ssl_client_cert | Path to the client cerificate in PEM format | | |
|
||||||
|
ssl_client_key | Path to the client public key in PEM format | | |
|
||||||
|
|
||||||
|
|
@ -614,6 +614,8 @@ char line[400];
|
|||||||
continue;
|
continue;
|
||||||
name = strtok_r(line, "=", &brkt);
|
name = strtok_r(line, "=", &brkt);
|
||||||
value = strtok_r(NULL, "=", &brkt);
|
value = strtok_r(NULL, "=", &brkt);
|
||||||
|
if (name && value)
|
||||||
|
{
|
||||||
if (strcmp(name, "hostname") == 0)
|
if (strcmp(name, "hostname") == 0)
|
||||||
*hostname = strdup(value);
|
*hostname = strdup(value);
|
||||||
else if (strcmp(name, "port") == 0)
|
else if (strcmp(name, "port") == 0)
|
||||||
@ -628,5 +630,12 @@ char line[400];
|
|||||||
"parameter '%s' in .maxadmin file\n", name);
|
"parameter '%s' in .maxadmin file\n", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "WARNING: Expected name=value "
|
||||||
|
"parameters in .maxadmin file but found "
|
||||||
|
"'%s'.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ macro(check_dirs)
|
|||||||
|
|
||||||
if(DEFINED MYSQL_DIR)
|
if(DEFINED MYSQL_DIR)
|
||||||
debugmsg("Searching for MySQL headers at: ${MYSQL_DIR}")
|
debugmsg("Searching for MySQL headers at: ${MYSQL_DIR}")
|
||||||
|
list(APPEND CMAKE_INCLUDE_PATH ${MYSQL_DIR})
|
||||||
find_path(MYSQL_DIR_LOC mysql.h PATHS ${MYSQL_DIR} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH)
|
find_path(MYSQL_DIR_LOC mysql.h PATHS ${MYSQL_DIR} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH)
|
||||||
else()
|
else()
|
||||||
find_path(MYSQL_DIR_LOC mysql.h PATH_SUFFIXES mysql mariadb)
|
find_path(MYSQL_DIR_LOC mysql.h PATH_SUFFIXES mysql mariadb)
|
||||||
|
@ -250,6 +250,8 @@ typedef struct router_instance {
|
|||||||
char *user; /*< User name to use with master */
|
char *user; /*< User name to use with master */
|
||||||
char *password; /*< Password to use with master */
|
char *password; /*< Password to use with master */
|
||||||
char *fileroot; /*< Root of binlog filename */
|
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 *master; /*< DCB for master connection */
|
||||||
DCB *client; /*< DCB for dummy client */
|
DCB *client; /*< DCB for dummy client */
|
||||||
SESSION *session; /*< Fake session for master connection */
|
SESSION *session; /*< Fake session for master connection */
|
||||||
|
@ -181,6 +181,8 @@ unsigned char *defuuid;
|
|||||||
spinlock_init(&inst->binlog_lock);
|
spinlock_init(&inst->binlog_lock);
|
||||||
|
|
||||||
inst->binlog_fd = -1;
|
inst->binlog_fd = -1;
|
||||||
|
inst->master_chksum = true;
|
||||||
|
inst->master_uuid = NULL;
|
||||||
|
|
||||||
inst->low_water = DEF_LOW_WATER;
|
inst->low_water = DEF_LOW_WATER;
|
||||||
inst->high_water = DEF_HIGH_WATER;
|
inst->high_water = DEF_HIGH_WATER;
|
||||||
@ -192,10 +194,12 @@ unsigned char *defuuid;
|
|||||||
inst->binlogdir = NULL;
|
inst->binlogdir = NULL;
|
||||||
inst->heartbeat = 300; // Default is every 5 minutes
|
inst->heartbeat = 300; // Default is every 5 minutes
|
||||||
|
|
||||||
|
inst->user = strdup(service->credentials.name);
|
||||||
|
inst->password = strdup(service->credentials.authdata);
|
||||||
|
|
||||||
my_uuid_init((ulong)rand()*12345,12345);
|
my_uuid_init((ulong)rand()*12345,12345);
|
||||||
if ((defuuid = (char *)malloc(20)) != NULL)
|
if ((defuuid = (char *)malloc(20)) != NULL)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
my_uuid(defuuid);
|
my_uuid(defuuid);
|
||||||
if ((inst->uuid = (char *)malloc(38)) != NULL)
|
if ((inst->uuid = (char *)malloc(38)) != NULL)
|
||||||
sprintf(inst->uuid, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
sprintf(inst->uuid, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||||
@ -268,6 +272,10 @@ unsigned char *defuuid;
|
|||||||
{
|
{
|
||||||
inst->password = strdup(value);
|
inst->password = strdup(value);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(options[i], "passwd") == 0)
|
||||||
|
{
|
||||||
|
inst->password = strdup(value);
|
||||||
|
}
|
||||||
else if (strcmp(options[i], "master-id") == 0)
|
else if (strcmp(options[i], "master-id") == 0)
|
||||||
{
|
{
|
||||||
inst->masterid = atoi(value);
|
inst->masterid = atoi(value);
|
||||||
@ -342,10 +350,16 @@ unsigned char *defuuid;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inst->fileroot == NULL)
|
}
|
||||||
inst->fileroot = strdup(BINLOG_NAME_ROOT);
|
else
|
||||||
|
{
|
||||||
|
LOGIF(LE, (skygw_log_write(
|
||||||
|
LOGFILE_ERROR, "%s: No router options supplied for binlogrouter",
|
||||||
|
service->name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inst->fileroot == NULL)
|
||||||
|
inst->fileroot = strdup(BINLOG_NAME_ROOT);
|
||||||
inst->active_logs = 0;
|
inst->active_logs = 0;
|
||||||
inst->reconnect_pending = 0;
|
inst->reconnect_pending = 0;
|
||||||
inst->handling_threads = 0;
|
inst->handling_threads = 0;
|
||||||
@ -969,6 +983,24 @@ ROUTER_INSTANCE *router = (ROUTER_INSTANCE *)instance;
|
|||||||
int error, len;
|
int error, len;
|
||||||
char msg[85], *errmsg;
|
char msg[85], *errmsg;
|
||||||
|
|
||||||
|
if (action == ERRACT_RESET)
|
||||||
|
{
|
||||||
|
backend_dcb->dcb_errhandle_called = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Don't handle same error twice on same DCB */
|
||||||
|
if (backend_dcb->dcb_errhandle_called)
|
||||||
|
{
|
||||||
|
/** we optimistically assume that previous call succeed */
|
||||||
|
*succp = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backend_dcb->dcb_errhandle_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
len = sizeof(error);
|
len = sizeof(error);
|
||||||
if (router->master && getsockopt(router->master->fd, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error != 0)
|
if (router->master && getsockopt(router->master->fd, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error != 0)
|
||||||
{
|
{
|
||||||
|
@ -354,6 +354,10 @@ int n;
|
|||||||
unsigned long filelen = 0;
|
unsigned long filelen = 0;
|
||||||
struct stat statb;
|
struct stat statb;
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (fstat(file->fd, &statb) == 0)
|
if (fstat(file->fd, &statb) == 0)
|
||||||
filelen = statb.st_size;
|
filelen = statb.st_size;
|
||||||
if (pos >= filelen)
|
if (pos >= filelen)
|
||||||
|
@ -79,6 +79,8 @@ void blr_extract_header(uint8_t *pkt, REP_HEADER *hdr);
|
|||||||
inline uint32_t extract_field(uint8_t *src, int bits);
|
inline uint32_t extract_field(uint8_t *src, int bits);
|
||||||
static void blr_log_packet(logfile_id_t file, char *msg, uint8_t *ptr, int len);
|
static void blr_log_packet(logfile_id_t file, char *msg, uint8_t *ptr, int len);
|
||||||
static void blr_master_close(ROUTER_INSTANCE *);
|
static void blr_master_close(ROUTER_INSTANCE *);
|
||||||
|
static char *blr_extract_column(GWBUF *buf, int col);
|
||||||
|
|
||||||
static int keepalive = 1;
|
static int keepalive = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -314,6 +316,7 @@ char query[128];
|
|||||||
"Invalid master state machine state (%d) for binlog router.",
|
"Invalid master state machine state (%d) for binlog router.",
|
||||||
router->master_state)));
|
router->master_state)));
|
||||||
gwbuf_consume(buf, gwbuf_length(buf));
|
gwbuf_consume(buf, gwbuf_length(buf));
|
||||||
|
|
||||||
spinlock_acquire(&router->lock);
|
spinlock_acquire(&router->lock);
|
||||||
if (router->reconnect_pending)
|
if (router->reconnect_pending)
|
||||||
{
|
{
|
||||||
@ -335,7 +338,20 @@ char query[128];
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (router->master_state != BLRM_BINLOGDUMP && MYSQL_RESPONSE_ERR(buf))
|
if (router->master_state == BLRM_GTIDMODE && MYSQL_RESPONSE_ERR(buf))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we get an error response to the GTID Mode then we
|
||||||
|
* asusme the server does not support GTID modes and
|
||||||
|
* continue. The error is saved and replayed to slaves if
|
||||||
|
* they also request the GTID mode.
|
||||||
|
*/
|
||||||
|
LOGIF(LE, (skygw_log_write(
|
||||||
|
LOGFILE_ERROR,
|
||||||
|
"%s: Master server does not support GTID Mode.",
|
||||||
|
router->service->name)));
|
||||||
|
}
|
||||||
|
else if (router->master_state != BLRM_BINLOGDUMP && MYSQL_RESPONSE_ERR(buf))
|
||||||
{
|
{
|
||||||
LOGIF(LE, (skygw_log_write(
|
LOGIF(LE, (skygw_log_write(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
@ -370,6 +386,9 @@ char query[128];
|
|||||||
router->retry_backoff = 1;
|
router->retry_backoff = 1;
|
||||||
break;
|
break;
|
||||||
case BLRM_SERVERID:
|
case BLRM_SERVERID:
|
||||||
|
{
|
||||||
|
char *val = blr_extract_column(buf, 1);
|
||||||
|
|
||||||
// Response to fetch of master's server-id
|
// Response to fetch of master's server-id
|
||||||
if (router->saved_master.server_id)
|
if (router->saved_master.server_id)
|
||||||
GWBUF_CONSUME_ALL(router->saved_master.server_id);
|
GWBUF_CONSUME_ALL(router->saved_master.server_id);
|
||||||
@ -384,6 +403,7 @@ char query[128];
|
|||||||
router->master_state = BLRM_HBPERIOD;
|
router->master_state = BLRM_HBPERIOD;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case BLRM_HBPERIOD:
|
case BLRM_HBPERIOD:
|
||||||
// Response to set the heartbeat period
|
// Response to set the heartbeat period
|
||||||
if (router->saved_master.heartbeat)
|
if (router->saved_master.heartbeat)
|
||||||
@ -405,6 +425,15 @@ char query[128];
|
|||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_CHKSUM2:
|
case BLRM_CHKSUM2:
|
||||||
|
{
|
||||||
|
char *val = blr_extract_column(buf, 1);
|
||||||
|
|
||||||
|
if (val && strncasecmp(val, "NONE", 4) == 0)
|
||||||
|
{
|
||||||
|
router->master_chksum = false;
|
||||||
|
}
|
||||||
|
if (val)
|
||||||
|
free(val);
|
||||||
// Response to the master_binlog_checksum, should be stored
|
// Response to the master_binlog_checksum, should be stored
|
||||||
if (router->saved_master.chksum2)
|
if (router->saved_master.chksum2)
|
||||||
GWBUF_CONSUME_ALL(router->saved_master.chksum2);
|
GWBUF_CONSUME_ALL(router->saved_master.chksum2);
|
||||||
@ -414,6 +443,7 @@ char query[128];
|
|||||||
router->master_state = BLRM_GTIDMODE;
|
router->master_state = BLRM_GTIDMODE;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case BLRM_GTIDMODE:
|
case BLRM_GTIDMODE:
|
||||||
// Response to the GTID_MODE, should be stored
|
// Response to the GTID_MODE, should be stored
|
||||||
if (router->saved_master.gtid_mode)
|
if (router->saved_master.gtid_mode)
|
||||||
@ -425,6 +455,10 @@ char query[128];
|
|||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_MUUID:
|
case BLRM_MUUID:
|
||||||
|
{
|
||||||
|
char *val = blr_extract_column(buf, 1);
|
||||||
|
router->master_uuid = val;
|
||||||
|
|
||||||
// Response to the SERVER_UUID, should be stored
|
// Response to the SERVER_UUID, should be stored
|
||||||
if (router->saved_master.uuid)
|
if (router->saved_master.uuid)
|
||||||
GWBUF_CONSUME_ALL(router->saved_master.uuid);
|
GWBUF_CONSUME_ALL(router->saved_master.uuid);
|
||||||
@ -435,6 +469,7 @@ char query[128];
|
|||||||
router->master_state = BLRM_SUUID;
|
router->master_state = BLRM_SUUID;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case BLRM_SUUID:
|
case BLRM_SUUID:
|
||||||
// Response to the SET @server_uuid, should be stored
|
// Response to the SET @server_uuid, should be stored
|
||||||
if (router->saved_master.setslaveuuid)
|
if (router->saved_master.setslaveuuid)
|
||||||
@ -860,6 +895,8 @@ static REP_HEADER phdr;
|
|||||||
* First check that the checksum we calculate matches the
|
* First check that the checksum we calculate matches the
|
||||||
* checksum in the packet we received.
|
* checksum in the packet we received.
|
||||||
*/
|
*/
|
||||||
|
if (router->master_chksum)
|
||||||
|
{
|
||||||
uint32_t chksum, pktsum;
|
uint32_t chksum, pktsum;
|
||||||
|
|
||||||
chksum = crc32(0L, NULL, 0);
|
chksum = crc32(0L, NULL, 0);
|
||||||
@ -885,6 +922,7 @@ static REP_HEADER phdr;
|
|||||||
blr_master_delayed_connect(router);
|
blr_master_delayed_connect(router);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
router->stats.n_binlogs++;
|
router->stats.n_binlogs++;
|
||||||
router->lastEventReceived = hdr.event_type;
|
router->lastEventReceived = hdr.event_type;
|
||||||
|
|
||||||
@ -1384,3 +1422,59 @@ blr_master_connected(ROUTER_INSTANCE *router)
|
|||||||
{
|
{
|
||||||
return router->master_state == BLRM_BINLOGDUMP;
|
return router->master_state == BLRM_BINLOGDUMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a result value from the set of messages that make up a
|
||||||
|
* MySQL response packet.
|
||||||
|
*
|
||||||
|
* @param buf The GWBUF containing the response
|
||||||
|
* @param col The column number to return
|
||||||
|
* @return The result form the column or NULL. The caller must free the result
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
blr_extract_column(GWBUF *buf, int col)
|
||||||
|
{
|
||||||
|
uint8_t *ptr;
|
||||||
|
int len, ncol, collen;
|
||||||
|
char *rval;
|
||||||
|
|
||||||
|
ptr = (uint8_t *)GWBUF_DATA(buf);
|
||||||
|
/* First packet should be the column count */
|
||||||
|
len = EXTRACT24(ptr);
|
||||||
|
ptr += 3;
|
||||||
|
if (*ptr != 1) // Check sequence number is 1
|
||||||
|
return NULL;
|
||||||
|
ptr++;
|
||||||
|
ncol = *ptr++;
|
||||||
|
if (ncol < col) // Not that many column in result
|
||||||
|
return NULL;
|
||||||
|
// Now ptr points at the column definition
|
||||||
|
while (ncol-- > 0)
|
||||||
|
{
|
||||||
|
len = EXTRACT24(ptr);
|
||||||
|
ptr += 4; // Skip to payload
|
||||||
|
ptr += len; // Skip over payload
|
||||||
|
}
|
||||||
|
// Now we should have an EOF packet
|
||||||
|
len = EXTRACT24(ptr);
|
||||||
|
ptr += 4; // Skip to payload
|
||||||
|
if (*ptr != 0xfe)
|
||||||
|
return NULL;
|
||||||
|
ptr += len;
|
||||||
|
|
||||||
|
// Finally we have reached the row
|
||||||
|
len = EXTRACT24(ptr);
|
||||||
|
ptr += 4;
|
||||||
|
while (--col > 0)
|
||||||
|
{
|
||||||
|
collen = *ptr++;
|
||||||
|
ptr += collen;
|
||||||
|
}
|
||||||
|
collen = *ptr++;
|
||||||
|
if ((rval = malloc(collen + 1)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
memcpy(rval, ptr, collen);
|
||||||
|
rval[collen] = 0; // NULL terminate
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
@ -70,6 +70,7 @@ static void blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
|||||||
static int blr_slave_send_maxscale_version(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
static int blr_slave_send_maxscale_version(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||||
static int blr_slave_send_maxscale_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
static int blr_slave_send_maxscale_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||||
static int blr_slave_send_master_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
static int blr_slave_send_master_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||||
|
static int blr_slave_send_slave_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||||
static int blr_slave_send_slave_hosts(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
static int blr_slave_send_slave_hosts(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||||
static int blr_slave_send_fieldcount(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, int count);
|
static int blr_slave_send_fieldcount(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, int count);
|
||||||
static int blr_slave_send_columndef(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *name, int type, int len, uint8_t seqno);
|
static int blr_slave_send_columndef(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *name, int type, int len, uint8_t seqno);
|
||||||
@ -330,7 +331,7 @@ 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);
|
return blr_slave_send_slave_status(router, slave);
|
||||||
}
|
}
|
||||||
else if (strcasecmp(word, "HOSTS") == 0)
|
else if (strcasecmp(word, "HOSTS") == 0)
|
||||||
{
|
{
|
||||||
@ -634,6 +635,284 @@ int len, file_len;
|
|||||||
return blr_slave_send_eof(router, slave, 9);
|
return blr_slave_send_eof(router, slave, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Columns to send for a "SHOW SLAVE STATUS" command
|
||||||
|
*/
|
||||||
|
static char *slave_status_columns[] = {
|
||||||
|
"Slave_IO_State", "Master_Host", "Master_User", "Master_Port", "Connect_Retry",
|
||||||
|
"Master_Log_File", "Read_Master_Log_Pos", "Relay_Log_File", "Relay_Log_Pos",
|
||||||
|
"Relay_Master_Log_File", "Slave_IO_Running", "Slave_SQL_Running", "Replicate_Do_DB",
|
||||||
|
"Replicate_Ignore_DB", "Replicate_Do_Table",
|
||||||
|
"Replicate_Ignore_Table", "Replicate_Wild_Do_Table", "Replicate_Wild_Ignore_Table",
|
||||||
|
"Last_Errno", "Last_Error", "Skip_Counter", "Exec_Master_Log_Pos", "Relay_Log_Space",
|
||||||
|
"Until_Condition", "Until_Log_File", "Until_Log_Pos", "Master_SSL_Allowed",
|
||||||
|
"Master_SSL_CA_File", "Master_SSL_CA_Path", "Master_SSL_Cert", "Master_SSL_Cipher",
|
||||||
|
"Master_SSL_Key",
|
||||||
|
"Seconds_Behind_Master", "Last_IO_Errno", "Last_IO_Error", "Last_SQL_Errno",
|
||||||
|
"Last_SQL_Error", "Replicate_Ignore_Server_Ids", "Master_Server_Id", "Master_UUID",
|
||||||
|
"Master_Info_File", "SQL_Delay", "SQL_Remaining_Delay", "Slave_SQL_Running_State",
|
||||||
|
"Master_Retry_Count", "Master_Bind", "Last_IO_Error_TimeStamp",
|
||||||
|
"Last_SQL_Error_Timestamp", "Master_SSL_Crl", "Master_SSL_Crlpath",
|
||||||
|
"Retrieved_Gtid_Set", "Executed_Gtid_Set", "Auto_Position", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the response to the SQL command "SHOW SLAVE STATUS"
|
||||||
|
*
|
||||||
|
* @param router The binlog router instance
|
||||||
|
* @param slave The slave server to which we are sending the response
|
||||||
|
* @return Non-zero if data was sent
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
blr_slave_send_slave_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||||
|
{
|
||||||
|
GWBUF *pkt;
|
||||||
|
char column[42];
|
||||||
|
uint8_t *ptr;
|
||||||
|
int len, actual_len, col_len, seqno, ncols, i;
|
||||||
|
|
||||||
|
/* Count the columns */
|
||||||
|
for (ncols = 0; slave_status_columns[ncols]; ncols++);
|
||||||
|
|
||||||
|
blr_slave_send_fieldcount(router, slave, ncols);
|
||||||
|
seqno = 2;
|
||||||
|
for (i = 0; slave_status_columns[i]; i++)
|
||||||
|
blr_slave_send_columndef(router, slave, slave_status_columns[i], 0xf, 40, seqno++);
|
||||||
|
blr_slave_send_eof(router, slave, seqno++);
|
||||||
|
|
||||||
|
len = 5 + (ncols * 41); // Max length
|
||||||
|
if ((pkt = gwbuf_alloc(len)) == NULL)
|
||||||
|
return 0;
|
||||||
|
ptr = GWBUF_DATA(pkt);
|
||||||
|
encode_value(ptr, len - 4, 24); // Add length of data packet
|
||||||
|
ptr += 3;
|
||||||
|
*ptr++ = seqno++; // Sequence number in response
|
||||||
|
|
||||||
|
sprintf(column, "%s", blrm_states[router->master_state]);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%s", router->master->remote ? router->master->remote : "");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%s", router->user ? router->user : "");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%d", router->service->dbref->server->port);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%d", 60); // Connect retry
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%s", router->binlog_name);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%ld", router->binlog_position);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* We have no relay log, we relay the binlog, so we will send the same data */
|
||||||
|
sprintf(column, "%s", router->binlog_name);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%ld", router->binlog_position);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* We have no relay log, we relay the binlog, so we will send the same data */
|
||||||
|
sprintf(column, "%s", router->binlog_name);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
strcpy(column, "Yes");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
strcpy(column, "Yes");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0; // Send 6 empty values
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* Last error information */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* Skip_Counter */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%ld", router->binlog_position);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
sprintf(column, "%ld", router->binlog_position);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
strcpy(column, "None");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* Until_Log_Pos */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* Master_SSL_Allowed */
|
||||||
|
strcpy(column, "No");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0; // Empty SSL columns
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* Seconds_Behind_Master */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* Master_SSL_Verify_Server_Cert */
|
||||||
|
strcpy(column, "No");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* Last_IO_Error */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* Last_SQL_Error */
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
sprintf(column, "%s", router->master_uuid ?
|
||||||
|
router->master_uuid : router->uuid);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
/* SQL_Delay*/
|
||||||
|
sprintf(column, "%d", 0);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0xfb; // NULL value
|
||||||
|
|
||||||
|
/* Slave_Running_State */
|
||||||
|
strcpy(column, "Slave running");
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
/* Master_Retry_Count */
|
||||||
|
sprintf(column, "%d", 1000);
|
||||||
|
col_len = strlen(column);
|
||||||
|
*ptr++ = col_len; // Length of result string
|
||||||
|
strncpy((char *)ptr, column, col_len); // Result string
|
||||||
|
ptr += col_len;
|
||||||
|
|
||||||
|
*ptr++ = 0; // Send 5 empty values
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
// No GTID support send empty values
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
actual_len = ptr - (uint8_t *)GWBUF_DATA(pkt);
|
||||||
|
ptr = GWBUF_DATA(pkt);
|
||||||
|
encode_value(ptr, actual_len - 4, 24); // Add length of data packet
|
||||||
|
|
||||||
|
pkt = gwbuf_rtrim(pkt, len - actual_len); // Trim the buffer to the actual size
|
||||||
|
|
||||||
|
slave->dcb->func.write(slave->dcb, pkt);
|
||||||
|
return blr_slave_send_eof(router, slave, seqno++);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the response to the SQL command "SHOW SLAVE HOSTS"
|
* Send the response to the SQL command "SHOW SLAVE HOSTS"
|
||||||
*
|
*
|
||||||
@ -673,7 +952,7 @@ ROUTER_SLAVE *sptr;
|
|||||||
sprintf(host, "%s", sptr->hostname ? sptr->hostname : "");
|
sprintf(host, "%s", sptr->hostname ? sptr->hostname : "");
|
||||||
sprintf(port, "%d", sptr->port);
|
sprintf(port, "%d", sptr->port);
|
||||||
sprintf(master_id, "%d", router->serverid);
|
sprintf(master_id, "%d", router->serverid);
|
||||||
sprintf(slave_uuid, "%s", sptr->uuid);
|
sprintf(slave_uuid, "%s", sptr->uuid ? sptr->uuid : "");
|
||||||
len = 5 + strlen(server_id) + strlen(host) + strlen(port)
|
len = 5 + strlen(server_id) + strlen(host) + strlen(port)
|
||||||
+ strlen(master_id) + strlen(slave_uuid) + 5;
|
+ strlen(master_id) + strlen(slave_uuid) + 5;
|
||||||
if ((pkt = gwbuf_alloc(len)) == NULL)
|
if ((pkt = gwbuf_alloc(len)) == NULL)
|
||||||
@ -800,6 +1079,15 @@ uint32_t chksum;
|
|||||||
ptr = GWBUF_DATA(queue);
|
ptr = GWBUF_DATA(queue);
|
||||||
len = extract_field(ptr, 24);
|
len = extract_field(ptr, 24);
|
||||||
binlognamelen = len - 11;
|
binlognamelen = len - 11;
|
||||||
|
if (binlognamelen > BINLOG_FNAMELEN)
|
||||||
|
{
|
||||||
|
LOGIF(LE, (skygw_log_write(
|
||||||
|
LOGFILE_ERROR,
|
||||||
|
"blr_slave_binlog_dump truncating binlog filename "
|
||||||
|
"from %d to %d",
|
||||||
|
binlognamelen, BINLOG_FNAMELEN)));
|
||||||
|
binlognamelen = BINLOG_FNAMELEN;
|
||||||
|
}
|
||||||
ptr += 4; // Skip length and sequence number
|
ptr += 4; // Skip length and sequence number
|
||||||
if (*ptr++ != COM_BINLOG_DUMP)
|
if (*ptr++ != COM_BINLOG_DUMP)
|
||||||
{
|
{
|
||||||
@ -819,6 +1107,13 @@ uint32_t chksum;
|
|||||||
strncpy(slave->binlogfile, (char *)ptr, binlognamelen);
|
strncpy(slave->binlogfile, (char *)ptr, binlognamelen);
|
||||||
slave->binlogfile[binlognamelen] = 0;
|
slave->binlogfile[binlognamelen] = 0;
|
||||||
|
|
||||||
|
LOGIF(LD, (skygw_log_write(
|
||||||
|
LOGFILE_DEBUG,
|
||||||
|
"%s: COM_BINLOG_DUMP: binlog name '%s', length %d, "
|
||||||
|
"from position %d.", router->service->name,
|
||||||
|
slave->binlogfile, binlognamelen,
|
||||||
|
slave->binlog_pos)));
|
||||||
|
|
||||||
slave->seqno = 1;
|
slave->seqno = 1;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user