Bugzilla #455, MaxScale crashed due missing buffer type information in multi-buffer responses.

This commit is contained in:
VilhoRaatikka
2014-07-03 19:20:45 +03:00
parent a68d83ff7f
commit 39679447c9
6 changed files with 72 additions and 47 deletions

View File

@ -317,12 +317,23 @@ gwbuf_trim(GWBUF *buf, unsigned int n_bytes)
return buf; return buf;
} }
/**
* Set given type to all buffers on the list.
* *
* @param buf The shared buffer
* @param type Type to be added
*/
void gwbuf_set_type( void gwbuf_set_type(
GWBUF* buf, GWBUF* buf,
gwbuf_type_t type) gwbuf_type_t type)
{ {
CHK_GWBUF(buf); /** Set type consistenly to all buffers on the list */
buf->gwbuf_type |= type; while (buf != NULL)
{
CHK_GWBUF(buf);
buf->gwbuf_type |= type;
buf=buf->next;
}
} }

View File

@ -97,10 +97,13 @@ typedef struct router_object {
*/ */
#define ROUTER_VERSION { 1, 0, 0 } #define ROUTER_VERSION { 1, 0, 0 }
/**
* Router capability type. Indicates what kind of input router accepts.
*/
typedef enum router_capability_t { typedef enum router_capability_t {
RCAP_TYPE_UNDEFINED = 0, RCAP_TYPE_UNDEFINED = 0x00,
RCAP_TYPE_STMT_INPUT = (1 << 0), RCAP_TYPE_STMT_INPUT = 0x01, /*< statement per buffer */
RCAP_TYPE_PACKET_INPUT = (1 << 1) RCAP_TYPE_PACKET_INPUT = 0x02 /*< data as it was read from DCB */
} router_capability_t; } router_capability_t;

View File

@ -253,27 +253,30 @@ typedef struct server_command_st {
struct server_command_st* scom_next; struct server_command_st* scom_next;
} server_command_t; } server_command_t;
/* /**
* MySQL Protocol specific state data * MySQL Protocol specific state data.
*
* Protocol carries information from client side to backend side, such as
* MySQL session command information and history of earlier session commands.
*/ */
typedef struct { typedef struct {
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
skygw_chk_t protocol_chk_top; skygw_chk_t protocol_chk_top;
#endif #endif
int fd; /*< The socket descriptor */ int fd; /*< The socket descriptor */
struct dcb *owner_dcb; /*< The DCB of the socket struct dcb *owner_dcb; /*< The DCB of the socket
* we are running on */ * we are running on */
SPINLOCK protocol_lock; SPINLOCK protocol_lock;
server_command_t protocol_command; /*< list of active commands */ server_command_t protocol_command; /*< session command list */
server_command_t* protocol_cmd_history; /*< command history list */ server_command_t* protocol_cmd_history; /*< session command history */
mysql_auth_state_t protocol_auth_state; /*< Authentication status */ mysql_auth_state_t protocol_auth_state; /*< Authentication status */
uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble, uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble,
* created or received */ * created or received */
uint32_t server_capabilities; /*< server capabilities, uint32_t server_capabilities; /*< server capabilities,
* created or received */ * created or received */
uint32_t client_capabilities; /*< client capabilities, uint32_t client_capabilities; /*< client capabilities,
* created or received */ * created or received */
unsigned long tid; /*< MySQL Thread ID, in unsigned long tid; /*< MySQL Thread ID, in
* handshake */ * handshake */
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
skygw_chk_t protocol_chk_tail; skygw_chk_t protocol_chk_tail;

View File

@ -167,7 +167,7 @@ static int gw_read_backend_event(DCB *dcb) {
backend_protocol = (MySQLProtocol *) dcb->protocol; backend_protocol = (MySQLProtocol *) dcb->protocol;
CHK_PROTOCOL(backend_protocol); CHK_PROTOCOL(backend_protocol);
#if 1
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
"%lu [gw_read_backend_event] Read dcb %p fd %d protocol " "%lu [gw_read_backend_event] Read dcb %p fd %d protocol "
@ -177,7 +177,6 @@ static int gw_read_backend_event(DCB *dcb) {
dcb->fd, dcb->fd,
backend_protocol->protocol_auth_state, backend_protocol->protocol_auth_state,
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state)))); STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
#endif
/* backend is connected: /* backend is connected:
@ -420,13 +419,13 @@ static int gw_read_backend_event(DCB *dcb) {
/* reading MySQL command output from backend and writing to the client */ /* reading MySQL command output from backend and writing to the client */
{ {
GWBUF *read_buffer = NULL; GWBUF *read_buffer = NULL;
ROUTER_OBJECT *router = NULL; ROUTER_OBJECT *router = NULL;
ROUTER *router_instance = NULL; ROUTER *router_instance = NULL;
void *rsession = NULL; void *rsession = NULL;
SESSION *session = dcb->session; SESSION *session = dcb->session;
int nbytes_read = 0; int nbytes_read = 0;
CHK_SESSION(session); CHK_SESSION(session);
router = session->service->router; router = session->service->router;
router_instance = session->service->router_instance; router_instance = session->service->router_instance;
@ -1226,7 +1225,7 @@ static GWBUF* process_response_data (
/** Get command which was stored in gw_MySQLWrite_backend */ /** Get command which was stored in gw_MySQLWrite_backend */
p = DCB_PROTOCOL(dcb, MySQLProtocol); p = DCB_PROTOCOL(dcb, MySQLProtocol);
CHK_PROTOCOL(p); CHK_PROTOCOL(p);
/** All buffers processed here are sescmd responses */ /** All buffers processed here are sescmd responses */
gwbuf_set_type(readbuf, GWBUF_TYPE_SESCMD_RESPONSE); gwbuf_set_type(readbuf, GWBUF_TYPE_SESCMD_RESPONSE);

View File

@ -666,10 +666,11 @@ int gw_read_client_event(
case MYSQL_IDLE: case MYSQL_IDLE:
{ {
uint8_t cap = 0; uint8_t cap = 0;
uint8_t *ptr_buff = NULL; uint8_t* payload = NULL;
int mysql_command = -1;
bool stmt_input; /*< router input type */ bool stmt_input; /*< router input type */
ss_dassert(nbytes_read >= 5);
session = dcb->session; session = dcb->session;
ss_dassert( session!= NULL); ss_dassert( session!= NULL);
@ -685,13 +686,7 @@ int gw_read_client_event(
/* Now, we are assuming in the first buffer there is /* Now, we are assuming in the first buffer there is
* the information form mysql command */ * the information form mysql command */
ptr_buff = GWBUF_DATA(read_buffer); payload = GWBUF_DATA(read_buffer);
/* get mysql commang at fifth byte */
if (ptr_buff) {
ss_dassert(nbytes_read >= 5);
mysql_command = ptr_buff[4];
}
/** /**
* Without rsession there is no access to backend. * Without rsession there is no access to backend.
* COM_QUIT : close client dcb * COM_QUIT : close client dcb
@ -700,7 +695,7 @@ int gw_read_client_event(
if(rsession == NULL) if(rsession == NULL)
{ {
/** COM_QUIT */ /** COM_QUIT */
if (mysql_command == '\x01') if (MYSQL_IS_COM_QUIT(payload))
{ {
LOGIF(LD, (skygw_log_write_flush( LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG, LOGFILE_DEBUG,
@ -767,7 +762,7 @@ int gw_read_client_event(
} }
/** Route COM_QUIT to backend */ /** Route COM_QUIT to backend */
if (mysql_command == '\x01') if (MYSQL_IS_COM_QUIT(payload))
{ {
/** /**
* Sends COM_QUIT packets since buffer is already * Sends COM_QUIT packets since buffer is already
@ -1394,11 +1389,25 @@ static int route_by_statement(SESSION *session, GWBUF *readbuf)
{ {
int rc = -1; int rc = -1;
GWBUF* packetbuf; GWBUF* packetbuf;
#if defined(SS_DEBUG)
gwbuf_type_t prevtype;
GWBUF* tmpbuf;
tmpbuf = readbuf;
while (tmpbuf != NULL)
{
ss_dassert(GWBUF_IS_TYPE_MYSQL(tmpbuf));
tmpbuf=tmpbuf->next;
}
#endif
do do
{ {
ss_dassert(GWBUF_IS_TYPE_MYSQL(readbuf));
packetbuf = gw_MySQL_get_next_packet(&readbuf); packetbuf = gw_MySQL_get_next_packet(&readbuf);
ss_dassert(GWBUF_IS_TYPE_MYSQL(packetbuf));
if (packetbuf != NULL) if (packetbuf != NULL)
{ {
CHK_GWBUF(packetbuf); CHK_GWBUF(packetbuf);

View File

@ -738,9 +738,9 @@ static void* newSession(
client_rses->rses_master_ref = master_ref; client_rses->rses_master_ref = master_ref;
/* assert with master_host */ /* assert with master_host */
ss_dassert(master_ref && (master_ref->bref_backend->backend_server && SERVER_MASTER)); ss_dassert(master_ref && (master_ref->bref_backend->backend_server && SERVER_MASTER));
client_rses->rses_capabilities = RCAP_TYPE_STMT_INPUT;
client_rses->rses_backend_ref = backend_ref; client_rses->rses_backend_ref = backend_ref;
client_rses->rses_nbackends = router_nservers; /*< # of backend servers */ client_rses->rses_nbackends = router_nservers; /*< # of backend servers */
client_rses->rses_capabilities = RCAP_TYPE_STMT_INPUT;
router->stats.n_sessions += 1; router->stats.n_sessions += 1;
/** /**
@ -1052,6 +1052,9 @@ static int routeQuery(
{ {
rses_is_closed = true; rses_is_closed = true;
} }
ss_dassert(!GWBUF_IS_TYPE_UNDEFINED(querybuf));
packet = GWBUF_DATA(querybuf); packet = GWBUF_DATA(querybuf);
packet_type = packet[4]; packet_type = packet[4];
@ -1564,10 +1567,6 @@ static void clientReply (
*/ */
writebuf = sescmd_cursor_process_replies(writebuf, bref); writebuf = sescmd_cursor_process_replies(writebuf, bref);
} }
else
{
ss_dassert(false);
}
/** /**
* If response will be sent to client, decrease waiter count. * If response will be sent to client, decrease waiter count.
* This applies to session commands only. Counter decrement * This applies to session commands only. Counter decrement
@ -1818,11 +1817,11 @@ static bool select_connect_backend_servers(
{ {
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
"%lu [select_connect_backend_servers] Didn't find master ", "%lu [select_connect_backend_servers] Session %p doesn't "
"for session %p rses %p.", "currently have a master chosen. Proceeding to master "
"selection.",
pthread_self(), pthread_self(),
session, session)));
backend_ref)));
master_found = false; master_found = false;
master_connected = false; master_connected = false;
@ -2004,7 +2003,8 @@ static bool select_connect_backend_servers(
} }
} }
/* take the master_host for master */ /* take the master_host for master */
else if (master_host && (b->backend_server == master_host->backend_server)) else if (master_host &&
(b->backend_server == master_host->backend_server))
{ {
*p_master_ref = &backend_ref[i]; *p_master_ref = &backend_ref[i];