From fb09cbf1000ccb90062c2c316d4d9fc43d11dc42 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 7 Jul 2015 13:15:23 +0300 Subject: [PATCH] Fixed queries being routed when the session is already closing. --- server/core/buffer.c | 1 + server/modules/protocol/mysql_backend.c | 11 +- server/modules/protocol/mysql_client.c | 140 ++++++++++-------- server/modules/routing/readconnroute.c | 12 +- .../routing/readwritesplit/readwritesplit.c | 2 +- 5 files changed, 89 insertions(+), 77 deletions(-) diff --git a/server/core/buffer.c b/server/core/buffer.c index 4c788cdd2..c3adacd34 100644 --- a/server/core/buffer.c +++ b/server/core/buffer.c @@ -197,6 +197,7 @@ GWBUF *rval; rval->gwbuf_info = buf->gwbuf_info; rval->gwbuf_bufobj = buf->gwbuf_bufobj; rval->tail = rval; + rval->next = NULL; CHK_GWBUF(rval); return rval; } diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index 477ca4cf0..3a5e8f52b 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -1080,7 +1080,7 @@ gw_backend_hangup(DCB *dcb) len = sizeof(error); if (getsockopt(dcb->fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) == 0) { - if (error != 0) + if (error != 0 && ses_state != SESSION_STATE_STOPPING) { strerror_r(error, buf, 100); LOGIF(LE, (skygw_log_write_flush( @@ -1094,9 +1094,12 @@ gw_backend_hangup(DCB *dcb) goto retblock; } #if defined(SS_DEBUG) - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Backend hangup error handling."))); + if(ses_state != SESSION_STATE_STOPPING) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Backend hangup error handling."))); + } #endif router->handleError(router_instance, diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index c3e463139..bab5971a8 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -1092,7 +1092,8 @@ int gw_read_client_event( case MYSQL_IDLE: { uint8_t* payload = NULL; - + session_state_t ses_state; + session = dcb->session; ss_dassert(session!= NULL); @@ -1100,93 +1101,106 @@ int gw_read_client_event( { CHK_SESSION(session); } + spinlock_acquire(&session->ses_lock); + ses_state = session->state; + spinlock_release(&session->ses_lock); /* Now, we are assuming in the first buffer there is * the information form mysql command */ payload = GWBUF_DATA(read_buffer); - /** Route COM_QUIT to backend */ - if (MYSQL_IS_COM_QUIT(payload)) - { + if(ses_state == SESSION_STATE_ROUTER_READY) + { + /** Route COM_QUIT to backend */ + if (MYSQL_IS_COM_QUIT(payload)) + { /** - * Sends COM_QUIT packets since buffer is already - * created. A BREF_CLOSED flag is set so dcb_close won't - * send redundant COM_QUIT. - */ + * Sends COM_QUIT packets since buffer is already + * created. A BREF_CLOSED flag is set so dcb_close won't + * send redundant COM_QUIT. + */ SESSION_ROUTE_QUERY(session, read_buffer); /** - * Close router session which causes closing of backends. - */ + * Close router session which causes closing of backends. + */ dcb_close(dcb); - } - else - { + } + else + { /** Reset error handler when routing of the new query begins */ router->handleError(NULL, NULL, NULL, dcb, ERRACT_RESET, NULL); if (stmt_input) { - /** - * Feed each statement completely and separately - * to router. - */ - rc = route_by_statement(session, &read_buffer); - - if (read_buffer != NULL) - { - /** add incomplete mysql packet to read queue */ - dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, read_buffer); - } + /** + * Feed each statement completely and separately + * to router. + */ + rc = route_by_statement(session, &read_buffer); + + if (read_buffer != NULL) + { + /** add incomplete mysql packet to read queue */ + dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, read_buffer); + } } else { - /** Feed whole packet to router */ - rc = SESSION_ROUTE_QUERY(session, read_buffer); + /** Feed whole packet to router */ + rc = SESSION_ROUTE_QUERY(session, read_buffer); } - + /** Routing succeed */ if (rc) { - rc = 0; /**< here '0' means success */ + rc = 0; /**< here '0' means success */ } else { - bool succp; - GWBUF* errbuf; - /** - * Create error to be sent to client if session - * can't be continued. - */ - errbuf = mysql_create_custom_error( - 1, - 0, - "Routing failed. Session is closed."); - /** - * Ensure that there are enough backends - * available. - */ - router->handleError( - router_instance, - session->router_session, - errbuf, - dcb, - ERRACT_NEW_CONNECTION, - &succp); - gwbuf_free(errbuf); - /** - * If there are not enough backends close - * session - */ - if (!succp) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Routing the query failed. " - "Session will be closed."))); + bool succp; + GWBUF* errbuf; + /** + * Create error to be sent to client if session + * can't be continued. + */ + errbuf = mysql_create_custom_error( + 1, + 0, + "Routing failed. Session is closed."); + /** + * Ensure that there are enough backends + * available. + */ + router->handleError( + router_instance, + session->router_session, + errbuf, + dcb, + ERRACT_NEW_CONNECTION, + &succp); + gwbuf_free(errbuf); + /** + * If there are not enough backends close + * session + */ + if (!succp) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Routing the query failed. " + "Session will be closed."))); - dcb_close(dcb); - } + dcb_close(dcb); + } } - } + } + } + else + { + skygw_log_write_flush(LT,"Session received a query in state %s", + STRSESSIONSTATE(ses_state)); + while((read_buffer = GWBUF_CONSUME_ALL(read_buffer)) != NULL); + goto return_rc; + } goto return_rc; } /* MYSQL_IDLE */ break; diff --git a/server/modules/routing/readconnroute.c b/server/modules/routing/readconnroute.c index b4b080c16..48c78b2e2 100644 --- a/server/modules/routing/readconnroute.c +++ b/server/modules/routing/readconnroute.c @@ -723,16 +723,10 @@ routeQuery(ROUTER *instance, void *router_session, GWBUF *queue) SERVER_IS_DOWN(router_cli_ses->backend->server)) { LOGIF(LT, (skygw_log_write( - LOGFILE_TRACE, + LOGFILE_TRACE|LOGFILE_ERROR, "Error : Failed to route MySQL command %d to backend " - "server.", - mysql_command))); - skygw_log_write( - LOGFILE_ERROR, - "Error : Failed to route MySQL command %d to backend " - "server %s.", - mysql_command, - router_cli_ses->backend->server->unique_name); + "server.%s", + mysql_command,rses_is_closed ? " Session is closed." : ""))); rc = 0; goto return_rc; diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index be2fb68df..b35a674c4 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -3915,7 +3915,7 @@ static GWBUF* sescmd_cursor_clone_querybuf( } ss_dassert(scur->scmd_cur_cmd != NULL); - buf = gwbuf_clone(scur->scmd_cur_cmd->my_sescmd_buf); + buf = gwbuf_clone_all(scur->scmd_cur_cmd->my_sescmd_buf); CHK_GWBUF(buf); return buf;