Addition of cache for server responses. This allows cached responses to be sent
if there is no master avaiable when MaxScale starts
This commit is contained in:
@ -168,6 +168,9 @@ typedef struct gwbuf {
|
|||||||
/*< Consume a number of bytes in the buffer */
|
/*< Consume a number of bytes in the buffer */
|
||||||
#define GWBUF_CONSUME(b, bytes) ((b)->start = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->end : (void *)((char *)(b)->start + (bytes)));
|
#define GWBUF_CONSUME(b, bytes) ((b)->start = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->end : (void *)((char *)(b)->start + (bytes)));
|
||||||
|
|
||||||
|
/*< Consume a complete buffer */
|
||||||
|
#define GWBUF_CONSUME_ALL(b) gwbuf_consume((b), GWBUF_LENGTH((b)))
|
||||||
|
|
||||||
#define GWBUF_RTRIM(b, bytes) ((b)->end = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->start : (void *)((char *)(b)->end - (bytes)));
|
#define GWBUF_RTRIM(b, bytes) ((b)->end = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->start : (void *)((char *)(b)->end - (bytes)));
|
||||||
|
|
||||||
#define GWBUF_TYPE(b) (b)->gwbuf_type
|
#define GWBUF_TYPE(b) (b)->gwbuf_type
|
||||||
|
@ -207,6 +207,7 @@ typedef struct {
|
|||||||
time_t lastReply;
|
time_t lastReply;
|
||||||
uint64_t n_fakeevents; /*< Fake events not written to disk */
|
uint64_t n_fakeevents; /*< Fake events not written to disk */
|
||||||
uint64_t n_artificial; /*< Artificial events not written to disk */
|
uint64_t n_artificial; /*< Artificial events not written to disk */
|
||||||
|
int n_badcrc; /*< No. of bad CRC's from master */
|
||||||
uint64_t events[0x24]; /*< Per event counters */
|
uint64_t events[0x24]; /*< Per event counters */
|
||||||
uint64_t lastsample;
|
uint64_t lastsample;
|
||||||
int minno;
|
int minno;
|
||||||
|
@ -340,6 +340,24 @@ int i;
|
|||||||
inst->slaves = NULL;
|
inst->slaves = NULL;
|
||||||
inst->next = NULL;
|
inst->next = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read any cached response messages
|
||||||
|
*/
|
||||||
|
inst->saved_master.server_id = blr_cache_read_response(inst, "serverid");
|
||||||
|
inst->saved_master.heartbeat = blr_cache_read_response(inst, "heartbeat");
|
||||||
|
inst->saved_master.chksum1 = blr_cache_read_response(inst, "chksum1");
|
||||||
|
inst->saved_master.chksum2 = blr_cache_read_response(inst, "chksum2");
|
||||||
|
inst->saved_master.gtid_mode = blr_cache_read_response(inst, "gtidmode");
|
||||||
|
inst->saved_master.uuid = blr_cache_read_response(inst, "uuid");
|
||||||
|
inst->saved_master.setslaveuuid = blr_cache_read_response(inst, "ssuuid");
|
||||||
|
inst->saved_master.setnames = blr_cache_read_response(inst, "setnames");
|
||||||
|
inst->saved_master.utf8 = blr_cache_read_response(inst, "utf8");
|
||||||
|
inst->saved_master.select1 = blr_cache_read_response(inst, "select1");
|
||||||
|
inst->saved_master.selectver = blr_cache_read_response(inst, "selectver");
|
||||||
|
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");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise the binlog file and position
|
* Initialise the binlog file and position
|
||||||
*/
|
*/
|
||||||
@ -702,6 +720,8 @@ struct tm tm;
|
|||||||
router_inst->stats.n_binlogs_ses);
|
router_inst->stats.n_binlogs_ses);
|
||||||
dcb_printf(dcb, "\tTotal no. of binlog events received: %u\n",
|
dcb_printf(dcb, "\tTotal no. of binlog events received: %u\n",
|
||||||
router_inst->stats.n_binlogs);
|
router_inst->stats.n_binlogs);
|
||||||
|
dcb_printf(dcb, "\tNo. of bad CRC received from master: %u\n",
|
||||||
|
router_inst->stats.n_badcrc);
|
||||||
minno = router_inst->stats.minno - 1;
|
minno = router_inst->stats.minno - 1;
|
||||||
if (minno == -1)
|
if (minno == -1)
|
||||||
minno = 30;
|
minno = 30;
|
||||||
|
@ -290,7 +290,7 @@ blr_file_flush(ROUTER_INSTANCE *router)
|
|||||||
BLFILE *
|
BLFILE *
|
||||||
blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
|
blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
|
||||||
{
|
{
|
||||||
char *ptr, path[1024];
|
char path[1024];
|
||||||
BLFILE *file;
|
BLFILE *file;
|
||||||
|
|
||||||
spinlock_acquire(&router->fileslock);
|
spinlock_acquire(&router->fileslock);
|
||||||
@ -613,3 +613,85 @@ struct stat statb;
|
|||||||
return statb.st_size;
|
return statb.st_size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the response packet to a cache file so that MaxScale can respond
|
||||||
|
* even if there is no master running when MaxScale starts.
|
||||||
|
*
|
||||||
|
* @param router The instance of the router
|
||||||
|
* @param response The name of the response, used to name the cached file
|
||||||
|
* @param buf The buffer to written to the cache
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
blr_cache_response(ROUTER_INSTANCE *router, char *response, GWBUF *buf)
|
||||||
|
{
|
||||||
|
char path[4096], *ptr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
strcpy(path, "/usr/local/skysql/MaxScale");
|
||||||
|
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
||||||
|
{
|
||||||
|
strncpy(path, ptr, 4096);
|
||||||
|
}
|
||||||
|
strncat(path, "/", 4096);
|
||||||
|
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, response, 4096);
|
||||||
|
|
||||||
|
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
|
||||||
|
return;
|
||||||
|
write(fd, GWBUF_DATA(buf), GWBUF_LENGTH(buf));
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a cached copy of a master response message. This allows
|
||||||
|
* the router to start and serve any binlogs it already has on disk
|
||||||
|
* if the master is not available.
|
||||||
|
*
|
||||||
|
* @param router The router instance structure
|
||||||
|
* @param response The name of the response
|
||||||
|
* @return A pointer to a GWBUF structure
|
||||||
|
*/
|
||||||
|
GWBUF *
|
||||||
|
blr_cache_read_response(ROUTER_INSTANCE *router, char *response)
|
||||||
|
{
|
||||||
|
struct stat statb;
|
||||||
|
char path[4096], *ptr;
|
||||||
|
int fd;
|
||||||
|
GWBUF *buf;
|
||||||
|
|
||||||
|
strcpy(path, "/usr/local/skysql/MaxScale");
|
||||||
|
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
||||||
|
{
|
||||||
|
strncpy(path, ptr, 4096);
|
||||||
|
}
|
||||||
|
strncat(path, "/", 4096);
|
||||||
|
strncat(path, router->service->name, 4096);
|
||||||
|
strncat(path, "/.cache/", 4096);
|
||||||
|
strncat(path, response, 4096);
|
||||||
|
|
||||||
|
if ((fd = open(path, O_RDONLY)) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fstat(fd, &statb) != 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((buf = gwbuf_alloc(statb.st_size)) == NULL)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
read(fd, GWBUF_DATA(buf), statb.st_size);
|
||||||
|
close(fd);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <housekeeper.h>
|
#include <housekeeper.h>
|
||||||
|
#include <buffer.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -370,7 +371,10 @@ char query[128];
|
|||||||
break;
|
break;
|
||||||
case BLRM_SERVERID:
|
case BLRM_SERVERID:
|
||||||
// Response to fetch of master's server-id
|
// Response to fetch of master's server-id
|
||||||
|
if (router->saved_master.server_id)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.server_id);
|
||||||
router->saved_master.server_id = buf;
|
router->saved_master.server_id = buf;
|
||||||
|
blr_cache_response(router, "serverid", buf);
|
||||||
// TODO: Extract the value of server-id and place in router->master_id
|
// TODO: Extract the value of server-id and place in router->master_id
|
||||||
{
|
{
|
||||||
char str[80];
|
char str[80];
|
||||||
@ -382,35 +386,50 @@ char query[128];
|
|||||||
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)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.heartbeat);
|
||||||
router->saved_master.heartbeat = buf;
|
router->saved_master.heartbeat = buf;
|
||||||
|
blr_cache_response(router, "heartbeat", buf);
|
||||||
buf = blr_make_query("SET @master_binlog_checksum = @@global.binlog_checksum");
|
buf = blr_make_query("SET @master_binlog_checksum = @@global.binlog_checksum");
|
||||||
router->master_state = BLRM_CHKSUM1;
|
router->master_state = BLRM_CHKSUM1;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_CHKSUM1:
|
case BLRM_CHKSUM1:
|
||||||
// Response to set the master binlog checksum
|
// Response to set the master binlog checksum
|
||||||
|
if (router->saved_master.chksum1)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.chksum1);
|
||||||
router->saved_master.chksum1 = buf;
|
router->saved_master.chksum1 = buf;
|
||||||
|
blr_cache_response(router, "chksum1", buf);
|
||||||
buf = blr_make_query("SELECT @master_binlog_checksum");
|
buf = blr_make_query("SELECT @master_binlog_checksum");
|
||||||
router->master_state = BLRM_CHKSUM2;
|
router->master_state = BLRM_CHKSUM2;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_CHKSUM2:
|
case BLRM_CHKSUM2:
|
||||||
// Response to the master_binlog_checksum, should be stored
|
// Response to the master_binlog_checksum, should be stored
|
||||||
|
if (router->saved_master.chksum2)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.chksum2);
|
||||||
router->saved_master.chksum2 = buf;
|
router->saved_master.chksum2 = buf;
|
||||||
|
blr_cache_response(router, "chksum2", buf);
|
||||||
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
|
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
|
||||||
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)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.gtid_mode);
|
||||||
router->saved_master.gtid_mode = buf;
|
router->saved_master.gtid_mode = buf;
|
||||||
|
blr_cache_response(router, "gtidmode", buf);
|
||||||
buf = blr_make_query("SHOW VARIABLES LIKE 'SERVER_UUID'");
|
buf = blr_make_query("SHOW VARIABLES LIKE 'SERVER_UUID'");
|
||||||
router->master_state = BLRM_MUUID;
|
router->master_state = BLRM_MUUID;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_MUUID:
|
case BLRM_MUUID:
|
||||||
// Response to the SERVER_UUID, should be stored
|
// Response to the SERVER_UUID, should be stored
|
||||||
|
if (router->saved_master.uuid)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.uuid);
|
||||||
router->saved_master.uuid = buf;
|
router->saved_master.uuid = buf;
|
||||||
|
blr_cache_response(router, "uuid", buf);
|
||||||
sprintf(query, "SET @slave_uuid='%s'", router->uuid);
|
sprintf(query, "SET @slave_uuid='%s'", router->uuid);
|
||||||
buf = blr_make_query(query);
|
buf = blr_make_query(query);
|
||||||
router->master_state = BLRM_SUUID;
|
router->master_state = BLRM_SUUID;
|
||||||
@ -418,56 +437,80 @@ char query[128];
|
|||||||
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)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.setslaveuuid);
|
||||||
router->saved_master.setslaveuuid = buf;
|
router->saved_master.setslaveuuid = buf;
|
||||||
|
blr_cache_response(router, "ssuuid", buf);
|
||||||
buf = blr_make_query("SET NAMES latin1");
|
buf = blr_make_query("SET NAMES latin1");
|
||||||
router->master_state = BLRM_LATIN1;
|
router->master_state = BLRM_LATIN1;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_LATIN1:
|
case BLRM_LATIN1:
|
||||||
// Response to the SET NAMES latin1, should be stored
|
// Response to the SET NAMES latin1, should be stored
|
||||||
|
if (router->saved_master.setnames)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.setnames);
|
||||||
router->saved_master.setnames = buf;
|
router->saved_master.setnames = buf;
|
||||||
|
blr_cache_response(router, "setnames", buf);
|
||||||
buf = blr_make_query("SET NAMES utf8");
|
buf = blr_make_query("SET NAMES utf8");
|
||||||
router->master_state = BLRM_UTF8;
|
router->master_state = BLRM_UTF8;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_UTF8:
|
case BLRM_UTF8:
|
||||||
// Response to the SET NAMES utf8, should be stored
|
// Response to the SET NAMES utf8, should be stored
|
||||||
|
if (router->saved_master.utf8)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.utf8);
|
||||||
router->saved_master.utf8 = buf;
|
router->saved_master.utf8 = buf;
|
||||||
|
blr_cache_response(router, "utf8", buf);
|
||||||
buf = blr_make_query("SELECT 1");
|
buf = blr_make_query("SELECT 1");
|
||||||
router->master_state = BLRM_SELECT1;
|
router->master_state = BLRM_SELECT1;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_SELECT1:
|
case BLRM_SELECT1:
|
||||||
// Response to the SELECT 1, should be stored
|
// Response to the SELECT 1, should be stored
|
||||||
|
if (router->saved_master.select1)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.select1);
|
||||||
router->saved_master.select1 = buf;
|
router->saved_master.select1 = buf;
|
||||||
|
blr_cache_response(router, "select1", buf);
|
||||||
buf = blr_make_query("SELECT VERSION();");
|
buf = blr_make_query("SELECT VERSION();");
|
||||||
router->master_state = BLRM_SELECTVER;
|
router->master_state = BLRM_SELECTVER;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_SELECTVER:
|
case BLRM_SELECTVER:
|
||||||
// Response to SELECT VERSION should be stored
|
// Response to SELECT VERSION should be stored
|
||||||
|
if (router->saved_master.selectver)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.selectver);
|
||||||
router->saved_master.selectver = buf;
|
router->saved_master.selectver = buf;
|
||||||
|
blr_cache_response(router, "selectver", buf);
|
||||||
buf = blr_make_query("SELECT @@version_comment limit 1;");
|
buf = blr_make_query("SELECT @@version_comment limit 1;");
|
||||||
router->master_state = BLRM_SELECTVERCOM;
|
router->master_state = BLRM_SELECTVERCOM;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_SELECTVERCOM:
|
case BLRM_SELECTVERCOM:
|
||||||
// Response to SELECT @@version_comment should be stored
|
// Response to SELECT @@version_comment should be stored
|
||||||
|
if (router->saved_master.selectvercom)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.selectvercom);
|
||||||
router->saved_master.selectvercom = buf;
|
router->saved_master.selectvercom = buf;
|
||||||
|
blr_cache_response(router, "selectvercom", buf);
|
||||||
buf = blr_make_query("SELECT @@hostname;");
|
buf = blr_make_query("SELECT @@hostname;");
|
||||||
router->master_state = BLRM_SELECTHOSTNAME;
|
router->master_state = BLRM_SELECTHOSTNAME;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_SELECTHOSTNAME:
|
case BLRM_SELECTHOSTNAME:
|
||||||
// Response to SELECT @@hostname should be stored
|
// Response to SELECT @@hostname should be stored
|
||||||
|
if (router->saved_master.selecthostname)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.selecthostname);
|
||||||
router->saved_master.selecthostname = buf;
|
router->saved_master.selecthostname = buf;
|
||||||
|
blr_cache_response(router, "selecthostname", buf);
|
||||||
buf = blr_make_query("SELECT @@max_allowed_packet;");
|
buf = blr_make_query("SELECT @@max_allowed_packet;");
|
||||||
router->master_state = BLRM_MAP;
|
router->master_state = BLRM_MAP;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
break;
|
break;
|
||||||
case BLRM_MAP:
|
case BLRM_MAP:
|
||||||
// Response to SELECT @@max_allowed_packet should be stored
|
// Response to SELECT @@max_allowed_packet should be stored
|
||||||
|
if (router->saved_master.map)
|
||||||
|
GWBUF_CONSUME_ALL(router->saved_master.map);
|
||||||
router->saved_master.map = buf;
|
router->saved_master.map = buf;
|
||||||
|
blr_cache_response(router, "map", buf);
|
||||||
buf = blr_make_registration(router);
|
buf = blr_make_registration(router);
|
||||||
router->master_state = BLRM_REGISTER;
|
router->master_state = BLRM_REGISTER;
|
||||||
router->master->func.write(router->master, buf);
|
router->master->func.write(router->master, buf);
|
||||||
@ -800,6 +843,34 @@ static REP_HEADER phdr;
|
|||||||
phdr = hdr;
|
phdr = hdr;
|
||||||
if (hdr.ok == 0)
|
if (hdr.ok == 0)
|
||||||
{
|
{
|
||||||
|
#define CHECK_CRC 1
|
||||||
|
#if CHECK_CRC
|
||||||
|
uint32_t chksum, pktsum;
|
||||||
|
|
||||||
|
chksum = crc32(0L, NULL, 0);
|
||||||
|
chksum = crc32(chksum, ptr + 5, hdr.event_size - 4);
|
||||||
|
pktsum = EXTRACT32(ptr + hdr.event_size + 1);
|
||||||
|
if (pktsum != chksum)
|
||||||
|
{
|
||||||
|
router->stats.n_badcrc++;
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
free(msg);
|
||||||
|
msg = NULL;
|
||||||
|
}
|
||||||
|
LOGIF(LE,(skygw_log_write(LOGFILE_ERROR,
|
||||||
|
"%s: Checksum error in event "
|
||||||
|
"from master, "
|
||||||
|
"binlog %s @ %d. "
|
||||||
|
"Closing master connection.",
|
||||||
|
router->service->name,
|
||||||
|
router->binlog_name,
|
||||||
|
router->binlog_position)));
|
||||||
|
blr_master_close(router);
|
||||||
|
blr_master_delayed_connect(router);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
router->stats.n_binlogs++;
|
router->stats.n_binlogs++;
|
||||||
router->lastEventReceived = hdr.event_type;
|
router->lastEventReceived = hdr.event_type;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user