From 040129002138af4e9cde953bf2b682ee5b9a1b74 Mon Sep 17 00:00:00 2001 From: vraatikka Date: Thu, 22 Aug 2013 10:42:18 +0300 Subject: [PATCH] Added spinlock ses_lock to struct SESSION to ensure that for each session closeSession is called only once. closeSession is called from mysql_backend.c:gw_read_backend_event, and from dcb.c:dcb_close. This is part of Bug #163. --- server/core/dcb.c | 26 +++++++++++++--- server/core/session.c | 1 + server/include/session.h | 3 ++ server/modules/protocol/mysql_backend.c | 41 ++++++++++++++++++------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/server/core/dcb.c b/server/core/dcb.c index 474579d59..0c358ad4a 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -611,11 +611,29 @@ dcb_close(DCB *dcb) */ SERVICE *service = dcb->session->service; - if (service && service->router && dcb->session->router_session) + if (service != NULL && + service->router != NULL && + dcb->session->router_session != NULL) { - service->router->closeSession( - service->router_instance, - dcb->session->router_session); + void* rsession = NULL; + /** + * Protect call of closeSession. + */ + spinlock_acquire(&dcb->session->ses_lock); + rsession = dcb->session->router_session; + dcb->session->router_session = NULL; + spinlock_release(&dcb->session->ses_lock); + + if (rsession != NULL) { + service->router->closeSession( + service->router_instance, + rsession); + } else { + skygw_log_write_flush( + LOGFILE_TRACE, + "%lu [dcb_close] rsession was NULL in dcb_close.", + pthread_self()); + } } session_free(dcb->session); } diff --git a/server/core/session.c b/server/core/session.c index 9a6bc796d..f48e6872d 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -59,6 +59,7 @@ SESSION *session; if ((session = (SESSION *)malloc(sizeof(SESSION))) == NULL) return NULL; + spinlock_init(&session->ses_lock); session->service = service; session->client = client; memset(&session->stats, 0, sizeof(SESSION_STATS)); diff --git a/server/include/session.h b/server/include/session.h index d6fe7ed2d..c91b837bd 100644 --- a/server/include/session.h +++ b/server/include/session.h @@ -33,6 +33,8 @@ * @endverbatim */ #include +#include +#include struct dcb; struct service; @@ -52,6 +54,7 @@ typedef struct { * and originating service together for the client session. */ typedef struct session { + SPINLOCK ses_lock; int state; /**< Current descriptor state */ struct dcb *client; /**< The client connection */ struct dcb *backends; /**< The set of backend servers */ diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index ebef69258..65a9f51dd 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -145,7 +145,7 @@ static int gw_read_backend_event(DCB *dcb) { current_session->user, current_session->client_sha1, backend_protocol); - + return 1; } @@ -163,13 +163,20 @@ static int gw_read_backend_event(DCB *dcb) { router_instance = session->service->router_instance; rsession = session->router_session; } - /* read backed auth reply */ rv = gw_receive_backend_auth(backend_protocol); switch (rv) { case MYSQL_FAILED_AUTHENTICATION: - fprintf(stderr, ">>>> Backend Auth failed for user [%s], fd %i\n", current_session->user, dcb->fd); + skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [gw_read_backend_event] caught " + "MYSQL_FAILED_AUTHENTICATION from " + "gw_receive_backend_auth. Fd %d, user %s. " + "Closing the session.", + pthread_self(), + dcb->fd, + current_session->user); backend_protocol->state = MYSQL_AUTH_FAILED; @@ -179,18 +186,30 @@ static int gw_read_backend_event(DCB *dcb) { 1, 0, "Connection to backend lost right now"); - - /* close the active session */ - router->closeSession(router_instance, rsession); - - /* force the router_session to NULL - * Later we will implement a proper status for the session - */ - session->router_session = NULL; + /** + * Protect call of closeSession. + */ + spinlock_acquire(&session->ses_lock); + rsession = session->router_session; + session->router_session = NULL; + spinlock_release(&session->ses_lock); + if (rsession != NULL) { + /* close the active session */ + router->closeSession(router_instance, rsession); + } return 1; case MYSQL_SUCCESFUL_AUTHENTICATION: + skygw_log_write_flush( + LOGFILE_TRACE, + "%lu [gw_read_backend_event] caught " + "MYSQL_SUCCESFUL_AUTHENTICATION from " + "gw_receive_backend_auth. Fd %d, user %s.", + pthread_self(), + dcb->fd, + current_session->user); + spinlock_acquire(&dcb->authlock); backend_protocol->state = MYSQL_IDLE;