Support for prepared statement, namely support for following comands : COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_RESET, COM_STMT_CLOSE, SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE (DEALLOCATE/DROP PREPARE stmt).
All prepare commands are executed in every backend server currently connected. All executes are routed to master. If stmt type was recorded in prepare phase in rwsplit router, read-only stmts could be routed to slaves. COM_STMT_PREPARE gets arbitrary number of response packets from backend database. Since statements are prepared in every backend server and only one multi-packet response can be replied to client, redundant multi-packet responses are discarded. This is done in router. Mechanisms from session command handling are utilized with little changes: router must identify when response consists of multiple packets so that it knows to calculate the number of packets in response and that it is able to discard correct number of packets. Information to the reply-handling router is provided by backend protocol, which includes a ordered list of commands of commands sent to protocol-owning backend server. A command is stored to protocol struct in mysql_backend.c:gw_MySQLWrite_backend if the statement buffer's type has GWBUF_TYPE_SINGLE_STMT set in mysql_client.c:route_by_statement. GWBUF_TYPE_SINGLE_STATEMENT indicates that there is single statement in the buffer, as opposite to Read Connection router, which accepts streaming input from client.
This commit is contained in:
@ -511,6 +511,7 @@ static skygw_query_type_t resolve_query_type(
|
||||
}
|
||||
/**<! fall through */
|
||||
case SQLCOM_CHANGE_DB:
|
||||
case SQLCOM_DEALLOCATE_PREPARE:
|
||||
type |= QUERY_TYPE_SESSION_WRITE;
|
||||
break;
|
||||
|
||||
|
@ -30,18 +30,36 @@
|
||||
*/
|
||||
|
||||
#include <dcb.h>
|
||||
#include <hashtable.h>
|
||||
|
||||
#undef PREP_STMT_CACHING
|
||||
|
||||
#if defined(PREP_STMT_CACHING)
|
||||
|
||||
typedef enum prep_stmt_type {
|
||||
PREP_STMT_NAME,
|
||||
PREP_STMT_ID
|
||||
} prep_stmt_type_t;
|
||||
|
||||
typedef enum prep_stmt_state {
|
||||
PREP_STMT_ALLOC,
|
||||
PREP_STMT_SENT,
|
||||
PREP_STMT_RECV,
|
||||
PREP_STMT_DROPPED
|
||||
} prep_stmt_state_t;
|
||||
|
||||
#endif /*< PREP_STMT_CACHING */
|
||||
|
||||
typedef enum bref_state {
|
||||
BREF_NOT_USED = 0x00,
|
||||
BREF_IN_USE = 0x01,
|
||||
BREF_WAITING_RESULT = 0x02, /*< for anything that responds */
|
||||
BREF_CLOSED = 0x04
|
||||
BREF_IN_USE = 0x01,
|
||||
BREF_WAITING_RESULT = 0x02, /*< for anything that responds */
|
||||
BREF_CLOSED = 0x04
|
||||
} bref_state_t;
|
||||
|
||||
#define BREF_IS_NOT_USED(s) (s->bref_state & BREF_NOT_USED)
|
||||
#define BREF_IS_IN_USE(s) (s->bref_state & BREF_IN_USE)
|
||||
#define BREF_IS_WAITING_RESULT(s) (s->bref_state & BREF_WAITING_RESULT)
|
||||
#define BREF_IS_CLOSED(s) (s->bref_state & BREF_CLOSED)
|
||||
#define BREF_IS_NOT_USED(s) (s->bref_state & ~BREF_IN_USE)
|
||||
#define BREF_IS_IN_USE(s) (s->bref_state & BREF_IN_USE)
|
||||
#define BREF_IS_WAITING_RESULT(s) (s->bref_state & BREF_WAITING_RESULT)
|
||||
#define BREF_IS_CLOSED(s) (s->bref_state & BREF_CLOSED)
|
||||
|
||||
typedef enum backend_type_t {
|
||||
BE_UNDEFINED=-1,
|
||||
@ -186,6 +204,25 @@ typedef struct rwsplit_config_st {
|
||||
} rwsplit_config_t;
|
||||
|
||||
|
||||
#if defined(PREP_STMT_CACHING)
|
||||
|
||||
typedef struct prep_stmt_st {
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t pstmt_chk_top;
|
||||
#endif
|
||||
union id {
|
||||
int seq;
|
||||
char* name;
|
||||
} pstmt_id;
|
||||
prep_stmt_state_t pstmt_state;
|
||||
prep_stmt_type_t pstmt_type;
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t pstmt_chk_tail;
|
||||
#endif
|
||||
} prep_stmt_t;
|
||||
|
||||
#endif /*< PREP_STMT_CACHING */
|
||||
|
||||
/**
|
||||
* The client session structure used within this router.
|
||||
*/
|
||||
@ -205,7 +242,9 @@ struct router_client_session {
|
||||
int rses_capabilities; /*< input type, for example */
|
||||
bool rses_autocommit_enabled;
|
||||
bool rses_transaction_active;
|
||||
uint64_t rses_id; /*< ID for router client session */
|
||||
#if defined(PREP_STMT_CACHING)
|
||||
HASHTABLE* rses_prep_stmt[2];
|
||||
#endif
|
||||
struct router_client_session* next;
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_chk_tail;
|
||||
|
@ -163,7 +163,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||
CHK_PROTOCOL(backend_protocol);
|
||||
|
||||
#if 1
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] Read dcb %p fd %d protocol "
|
||||
@ -171,8 +171,9 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->fd,
|
||||
backend_protocol->state,
|
||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
||||
backend_protocol->protocol_auth_state,
|
||||
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||
#endif
|
||||
|
||||
|
||||
/* backend is connected:
|
||||
@ -186,17 +187,18 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
* If starting to auhenticate with backend server, lock dcb
|
||||
* to prevent overlapping processing of auth messages.
|
||||
*/
|
||||
if (backend_protocol->state == MYSQL_CONNECTED) {
|
||||
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_CONNECTED)
|
||||
{
|
||||
spinlock_acquire(&dcb->authlock);
|
||||
|
||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||
CHK_PROTOCOL(backend_protocol);
|
||||
|
||||
if (backend_protocol->state == MYSQL_CONNECTED) {
|
||||
|
||||
if (gw_read_backend_handshake(backend_protocol) != 0) {
|
||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_CONNECTED)
|
||||
{
|
||||
if (gw_read_backend_handshake(backend_protocol) != 0)
|
||||
{
|
||||
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] after "
|
||||
@ -205,7 +207,9 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
pthread_self(),
|
||||
backend_protocol->owner_dcb->fd)));
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handshake decoded, send the auth credentials */
|
||||
if (gw_send_authentication_to_backend(
|
||||
current_session->db,
|
||||
@ -213,7 +217,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
current_session->client_sha1,
|
||||
backend_protocol) != 0)
|
||||
{
|
||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
||||
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] after "
|
||||
@ -221,31 +225,31 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
"fd %d, state = MYSQL_AUTH_FAILED.",
|
||||
pthread_self(),
|
||||
backend_protocol->owner_dcb->fd)));
|
||||
} else {
|
||||
backend_protocol->state = MYSQL_AUTH_RECV;
|
||||
}
|
||||
else
|
||||
{
|
||||
backend_protocol->protocol_auth_state = MYSQL_AUTH_RECV;
|
||||
}
|
||||
}
|
||||
}
|
||||
spinlock_release(&dcb->authlock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Now:
|
||||
* -- check the authentication reply from backend
|
||||
* OR
|
||||
* -- handle a previous handshake error
|
||||
*/
|
||||
if (backend_protocol->state == MYSQL_AUTH_RECV ||
|
||||
backend_protocol->state == MYSQL_AUTH_FAILED)
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV ||
|
||||
backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||
{
|
||||
spinlock_acquire(&dcb->authlock);
|
||||
|
||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||
CHK_PROTOCOL(backend_protocol);
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_RECV ||
|
||||
backend_protocol->state == MYSQL_AUTH_FAILED)
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV ||
|
||||
backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||
{
|
||||
ROUTER_OBJECT *router = NULL;
|
||||
ROUTER *router_instance = NULL;
|
||||
@ -259,7 +263,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
router_instance = session->service->router_instance;
|
||||
rsession = session->router_session;
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_RECV) {
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV) {
|
||||
/*<
|
||||
* Read backed auth reply
|
||||
*/
|
||||
@ -268,14 +272,14 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
switch (receive_rc) {
|
||||
case -1:
|
||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
||||
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] after "
|
||||
"gw_receive_backend_authentication "
|
||||
"fd %d, state = MYSQL_AUTH_FAILED.",
|
||||
backend_protocol->owner_dcb->fd,
|
||||
pthread_self())));
|
||||
pthread_self(),
|
||||
backend_protocol->owner_dcb->fd)));
|
||||
|
||||
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -286,7 +290,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
current_session->user)));
|
||||
break;
|
||||
case 1:
|
||||
backend_protocol->state = MYSQL_IDLE;
|
||||
backend_protocol->protocol_auth_state = MYSQL_IDLE;
|
||||
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
@ -316,7 +320,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_FAILED)
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||
{
|
||||
/**
|
||||
* protocol state won't change anymore,
|
||||
@ -338,9 +342,14 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
bool succp;
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Backend read error handling.")));
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] "
|
||||
"calling handleError. Backend "
|
||||
"DCB %p, session %p",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->session)));
|
||||
#endif
|
||||
|
||||
errbuf = mysql_create_custom_error(
|
||||
@ -358,6 +367,15 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
ss_dassert(!succp);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] "
|
||||
"after calling handleError. Backend "
|
||||
"DCB %p, session %p",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->session)));
|
||||
|
||||
if (session != NULL)
|
||||
{
|
||||
spinlock_acquire(&session->ses_lock);
|
||||
@ -371,7 +389,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(backend_protocol->state == MYSQL_IDLE);
|
||||
ss_dassert(backend_protocol->protocol_auth_state == MYSQL_IDLE);
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_backend_event] "
|
||||
@ -396,44 +414,31 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
/* reading MySQL command output from backend and writing to the client */
|
||||
{
|
||||
GWBUF *writebuf = NULL;
|
||||
ROUTER_OBJECT *router = NULL;
|
||||
ROUTER *router_instance = NULL;
|
||||
void *rsession = NULL;
|
||||
SESSION *session = dcb->session;
|
||||
|
||||
GWBUF *readbuf = NULL;
|
||||
ROUTER_OBJECT *router = NULL;
|
||||
ROUTER *router_instance = NULL;
|
||||
void *rsession = NULL;
|
||||
SESSION *session = dcb->session;
|
||||
int nbytes_read = 0;
|
||||
mysql_server_cmd_t srvcmd = MYSQL_COM_UNDEFINED;
|
||||
|
||||
CHK_SESSION(session);
|
||||
router = session->service->router;
|
||||
router_instance = session->service->router_instance;
|
||||
rsession = session->router_session;
|
||||
|
||||
/* read available backend data */
|
||||
rc = dcb_read(dcb, &writebuf);
|
||||
rc = dcb_read(dcb, &readbuf);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
/*< vraa : errorHandle */
|
||||
/*<
|
||||
* Backend generated EPOLLIN event and if backend has
|
||||
* failed, connection must be closed to avoid backend
|
||||
* dcb from getting hanged.
|
||||
*/
|
||||
GWBUF* errbuf;
|
||||
bool succp;
|
||||
/**
|
||||
* - send error for client
|
||||
* - mark failed backend BREF_NOT_USED
|
||||
* - go through all servers and select one according to
|
||||
* the criteria that user specified in the beginning.
|
||||
*/
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Backend read error handling #2.")));
|
||||
bool succp;
|
||||
#if defined(SS_DEBUG)
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Backend read error handling #2.")));
|
||||
#endif
|
||||
|
||||
|
||||
errbuf = mysql_create_custom_error(
|
||||
1,
|
||||
0,
|
||||
@ -456,33 +461,111 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
rc = 0;
|
||||
goto return_rc;
|
||||
}
|
||||
nbytes_read = gwbuf_length(readbuf);
|
||||
|
||||
if (writebuf == NULL) {
|
||||
rc = 0;
|
||||
if (nbytes_read == 0)
|
||||
{
|
||||
goto return_rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(readbuf != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ask for next response (1 or more packets) like in
|
||||
* gw_MySQL_get_next_packet but gw_MySQL_get_next_response
|
||||
*/
|
||||
srvcmd = protocol_get_srv_command((MySQLProtocol *)dcb->protocol,
|
||||
false);
|
||||
/**
|
||||
* If backend DCB is waiting for response to COM_STMT_PREPARE,
|
||||
* it, then only that must be passed to clientReply.
|
||||
*
|
||||
* If response consists of ses cmd response and response to
|
||||
* COM_STMT_PREPARE, there can't be anything after
|
||||
* COM_STMT_PREPARE response because whole buffer may be
|
||||
* discarded since router doesn't know the borderlines of MySQL
|
||||
* packets.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read all packets from <readbuf> which belong to STMT PREPARE
|
||||
* response.
|
||||
* Move packets not belonging to STMT PREPARE response to
|
||||
* dcb_readqueue.
|
||||
* When whole response is read, pass <readbuf> forward to
|
||||
* clientReply.
|
||||
*/
|
||||
if (srvcmd == MYSQL_COM_STMT_PREPARE)
|
||||
{
|
||||
MySQLProtocol* p;
|
||||
int nresponse_packets;
|
||||
GWBUF* tmpbuf;
|
||||
|
||||
p = (MySQLProtocol *)dcb->protocol;
|
||||
nresponse_packets = protocol_get_nresponse_packets(p);
|
||||
|
||||
/** count only once per response */
|
||||
if (nresponse_packets == 0)
|
||||
{
|
||||
nresponse_packets = get_stmt_nresponse_packets(
|
||||
readbuf,
|
||||
srvcmd);
|
||||
}
|
||||
tmpbuf = gw_MySQL_get_packets(&readbuf, &nresponse_packets);
|
||||
gwbuf_append(dcb->dcb_readqueue, readbuf);
|
||||
readbuf = tmpbuf;
|
||||
|
||||
/** <readbuf> contains incomplete response to STMT PREPARE */
|
||||
if (nresponse_packets != 0)
|
||||
{
|
||||
rc = 0;
|
||||
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Backend fd %d read incomplete response packet. "
|
||||
"Waiting %d more, cmd %s.",
|
||||
dcb->fd,
|
||||
nresponse_packets,
|
||||
STRPACKETTYPE(srvcmd))));
|
||||
/**
|
||||
* store the number of how many packets the
|
||||
* reponse consists of to backend's protocol.
|
||||
*/
|
||||
protocol_set_nresponse_packets(p, nresponse_packets);
|
||||
goto return_rc;
|
||||
}
|
||||
protocol_remove_srv_command((MySQLProtocol *)dcb->protocol);
|
||||
}
|
||||
/*<
|
||||
* If dcb->session->client is freed already it may be NULL.
|
||||
*/
|
||||
if (dcb->session->client != NULL) {
|
||||
if (dcb->session->client != NULL)
|
||||
{
|
||||
client_protocol = SESSION_PROTOCOL(dcb->session,
|
||||
MySQLProtocol);
|
||||
if (client_protocol != NULL) {
|
||||
if (client_protocol != NULL)
|
||||
{
|
||||
CHK_PROTOCOL(client_protocol);
|
||||
|
||||
if (client_protocol->state == MYSQL_IDLE)
|
||||
|
||||
if (client_protocol->protocol_auth_state ==
|
||||
MYSQL_IDLE)
|
||||
{
|
||||
gwbuf_set_type(writebuf, GWBUF_TYPE_MYSQL);
|
||||
gwbuf_set_type(readbuf, GWBUF_TYPE_MYSQL);
|
||||
|
||||
router->clientReply(router_instance,
|
||||
rsession,
|
||||
writebuf,
|
||||
readbuf,
|
||||
dcb);
|
||||
rc = 1;
|
||||
}
|
||||
goto return_rc;
|
||||
} else if (dcb->session->client->dcb_role == DCB_ROLE_INTERNAL) {
|
||||
gwbuf_set_type(writebuf, GWBUF_TYPE_MYSQL);
|
||||
router->clientReply(router_instance, rsession, writebuf, dcb);
|
||||
}
|
||||
else if (dcb->session->client->dcb_role == DCB_ROLE_INTERNAL)
|
||||
{
|
||||
gwbuf_set_type(readbuf, GWBUF_TYPE_MYSQL);
|
||||
router->clientReply(router_instance, rsession, readbuf, dcb);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
@ -548,8 +631,8 @@ static int gw_write_backend_event(DCB *dcb) {
|
||||
goto return_rc;
|
||||
}
|
||||
|
||||
if (backend_protocol->state == MYSQL_PENDING_CONNECT) {
|
||||
backend_protocol->state = MYSQL_CONNECTED;
|
||||
if (backend_protocol->protocol_auth_state == MYSQL_PENDING_CONNECT) {
|
||||
backend_protocol->protocol_auth_state = MYSQL_CONNECTED;
|
||||
rc = 1;
|
||||
goto return_rc;
|
||||
}
|
||||
@ -569,7 +652,7 @@ return_rc:
|
||||
}
|
||||
|
||||
/*
|
||||
* Write function for backend DCB
|
||||
* Write function for backend DCB. Store command to protocol.
|
||||
*
|
||||
* @param dcb The DCB of the backend
|
||||
* @param queue Queue of buffers to write
|
||||
@ -587,7 +670,7 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
* If auth failed, return value is 0, write and buffered write
|
||||
* return 1.
|
||||
*/
|
||||
switch(backend_protocol->state) {
|
||||
switch(backend_protocol->protocol_auth_state) {
|
||||
case MYSQL_AUTH_FAILED:
|
||||
{
|
||||
size_t len;
|
||||
@ -613,8 +696,12 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
goto return_rc;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case MYSQL_IDLE:
|
||||
{
|
||||
uint8_t* ptr = GWBUF_DATA(queue);
|
||||
int cmd = MYSQL_GET_COMMAND(ptr);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_MySQLWrite_backend] write to dcb %p "
|
||||
@ -622,18 +709,37 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->fd,
|
||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
||||
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||
spinlock_release(&dcb->authlock);
|
||||
|
||||
/**
|
||||
* Server commands are stored to MySQLProtocol structure
|
||||
* if buffer always includes a single statement. That
|
||||
* information is stored in GWBUF type field
|
||||
* (GWBUF_TYPE_SINGLE_STMT bit).
|
||||
*/
|
||||
if (GWBUF_IS_TYPE_SINGLE_STMT(queue))
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Write to backend's DCB fd %d "
|
||||
"cmd %s protocol state %s.",
|
||||
dcb->fd,
|
||||
STRPACKETTYPE(cmd),
|
||||
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||
/** Record the command to backend's protocol */
|
||||
protocol_add_srv_command(backend_protocol, cmd);
|
||||
}
|
||||
/** Write to backend */
|
||||
rc = dcb_write(dcb, queue);
|
||||
goto return_rc;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
/*<
|
||||
* Now put the incoming data to the delay queue unless backend is
|
||||
* connected with auth ok
|
||||
*/
|
||||
{
|
||||
uint8_t* ptr = GWBUF_DATA(queue);
|
||||
int cmd = MYSQL_GET_COMMAND(ptr);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_MySQLWrite_backend] delayed write to "
|
||||
@ -641,12 +747,36 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->fd,
|
||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
||||
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||
/**
|
||||
* Since it is known that buffer contains one complete
|
||||
* command, store the command to backend's protocol. When
|
||||
* backend server responses the command determines how
|
||||
* response needs to be processed. This is mainly due to
|
||||
* MYSQL_COM_STMT_PREPARE whose response consists of
|
||||
* arbitrary number of packets.
|
||||
*/
|
||||
if (GWBUF_IS_TYPE_SINGLE_STMT(queue))
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Write to backend's delayqueue fd %d "
|
||||
"protocol state %s.",
|
||||
dcb->fd,
|
||||
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||
/** Record the command to backend's protocol */
|
||||
protocol_add_srv_command(backend_protocol, cmd);
|
||||
}
|
||||
/*<
|
||||
* Now put the incoming data to the delay queue unless backend is
|
||||
* connected with auth ok
|
||||
*/
|
||||
backend_set_delayqueue(dcb, queue);
|
||||
spinlock_release(&dcb->authlock);
|
||||
rc = 1;
|
||||
goto return_rc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return_rc:
|
||||
return rc;
|
||||
@ -755,7 +885,7 @@ static int gw_create_backend_connection(
|
||||
case 0:
|
||||
ss_dassert(fd > 0);
|
||||
protocol->fd = fd;
|
||||
protocol->state = MYSQL_CONNECTED;
|
||||
protocol->protocol_auth_state = MYSQL_CONNECTED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_create_backend_connection] Established "
|
||||
@ -770,7 +900,7 @@ static int gw_create_backend_connection(
|
||||
|
||||
case 1:
|
||||
ss_dassert(fd > 0);
|
||||
protocol->state = MYSQL_PENDING_CONNECT;
|
||||
protocol->protocol_auth_state = MYSQL_PENDING_CONNECT;
|
||||
protocol->fd = fd;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
@ -785,7 +915,7 @@ static int gw_create_backend_connection(
|
||||
|
||||
default:
|
||||
ss_dassert(fd == -1);
|
||||
ss_dassert(protocol->state == MYSQL_ALLOC);
|
||||
ss_dassert(protocol->protocol_auth_state == MYSQL_ALLOC);
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_create_backend_connection] Connection "
|
||||
@ -955,7 +1085,7 @@ static int backend_write_delayqueue(DCB *dcb)
|
||||
rc = dcb_write(dcb, localq);
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
if (rc == 0)
|
||||
{
|
||||
GWBUF* errbuf;
|
||||
bool succp;
|
||||
|
@ -495,7 +495,7 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
int
|
||||
gw_MySQLWrite_client(DCB *dcb, GWBUF *queue)
|
||||
{
|
||||
return dcb_write(dcb, queue);
|
||||
return dcb_write(dcb, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -582,7 +582,7 @@ int gw_read_client_event(
|
||||
/**
|
||||
* Now there should be at least one complete mysql packet in read_buffer.
|
||||
*/
|
||||
switch (protocol->state) {
|
||||
switch (protocol->protocol_auth_state) {
|
||||
|
||||
case MYSQL_AUTH_SENT:
|
||||
{
|
||||
@ -595,7 +595,7 @@ int gw_read_client_event(
|
||||
if (auth_val == 0)
|
||||
{
|
||||
SESSION *session = NULL;
|
||||
protocol->state = MYSQL_AUTH_RECV;
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_RECV;
|
||||
/**
|
||||
* Create session, and a router session for it.
|
||||
* If successful, there will be backend connection(s)
|
||||
@ -607,7 +607,8 @@ int gw_read_client_event(
|
||||
{
|
||||
CHK_SESSION(session);
|
||||
ss_dassert(session->state != SESSION_STATE_ALLOC);
|
||||
protocol->state = MYSQL_IDLE;
|
||||
|
||||
protocol->protocol_auth_state = MYSQL_IDLE;
|
||||
/**
|
||||
* Send an AUTH_OK packet to the client,
|
||||
* packet sequence is # 2
|
||||
@ -616,7 +617,7 @@ int gw_read_client_event(
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol->state = MYSQL_AUTH_FAILED;
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_client_event] session "
|
||||
@ -637,7 +638,7 @@ int gw_read_client_event(
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol->state = MYSQL_AUTH_FAILED;
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_client_event] after "
|
||||
@ -888,8 +889,8 @@ int gw_write_client_event(DCB *dcb)
|
||||
}
|
||||
protocol = (MySQLProtocol *)dcb->protocol;
|
||||
CHK_PROTOCOL(protocol);
|
||||
|
||||
if (protocol->state == MYSQL_IDLE)
|
||||
|
||||
if (protocol->protocol_auth_state == MYSQL_IDLE)
|
||||
{
|
||||
dcb_drain_writeq(dcb);
|
||||
goto return_1;
|
||||
@ -1231,7 +1232,7 @@ int gw_MySQLAccept(DCB *listener)
|
||||
MySQLSendHandshake(client_dcb);
|
||||
|
||||
// client protocol state change
|
||||
protocol->state = MYSQL_AUTH_SENT;
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_SENT;
|
||||
|
||||
/**
|
||||
* Set new descriptor to event set. At the same time,
|
||||
@ -1289,8 +1290,15 @@ static int gw_error_client_event(
|
||||
SESSION* session;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
session = dcb->session;
|
||||
CHK_SESSION(session);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_error_client_event] Error event handling for DCB %p "
|
||||
"in state %s, session %p.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
(session != NULL ? session : NULL))));
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -1368,7 +1376,7 @@ gw_client_hangup_event(DCB *dcb)
|
||||
|
||||
/**
|
||||
* Detect if buffer includes partial mysql packet or multiple packets.
|
||||
* Store partial packet to pendingqueue. Send complete packets one by one
|
||||
* Store partial packet to dcb_readqueue. Send complete packets one by one
|
||||
* to router.
|
||||
*
|
||||
* It is assumed readbuf includes at least one complete packet.
|
||||
@ -1387,6 +1395,20 @@ static int route_by_statement(SESSION *session, GWBUF *readbuf)
|
||||
if (packetbuf != NULL)
|
||||
{
|
||||
CHK_GWBUF(packetbuf);
|
||||
/**
|
||||
* This means that buffer includes exactly one MySQL
|
||||
* statement.
|
||||
* backend func.write uses the information. MySQL backend
|
||||
* protocol, for example, stores the command identifier
|
||||
* to protocol structure. When some other thread reads
|
||||
* the corresponding response the command tells how to
|
||||
* handle response.
|
||||
*
|
||||
* Set it here instead of gw_read_client_event to make
|
||||
* sure it is set to each (MySQL) packet.
|
||||
*/
|
||||
gwbuf_set_type(packetbuf, GWBUF_TYPE_SINGLE_STMT);
|
||||
/** Route query */
|
||||
rc = SESSION_ROUTE_QUERY(session, packetbuf);
|
||||
}
|
||||
else
|
||||
|
@ -113,7 +113,7 @@ static void clientReply(
|
||||
static void handleError(
|
||||
ROUTER *instance,
|
||||
void *router_session,
|
||||
char *message,
|
||||
GWBUF *errbuf,
|
||||
DCB *backend_dcb,
|
||||
int action,
|
||||
bool *succp);
|
||||
@ -708,7 +708,7 @@ static void
|
||||
handleError(
|
||||
ROUTER *instance,
|
||||
void *router_session,
|
||||
char *message,
|
||||
GWBUF *errbuf,
|
||||
DCB *backend_dcb,
|
||||
int action,
|
||||
bool *succp)
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user