diff --git a/server/core/dcb.c b/server/core/dcb.c index 448c9a091..013029de6 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -346,7 +346,10 @@ dcb_final_free(DCB *dcb) local_session->client = NULL; spinlock_release(&local_session->ses_lock); } - session_free(local_session); + if (SESSION_STATE_DUMMY != local_session->state) + { + session_free(local_session); + } } } diff --git a/server/core/random_jkiss.c b/server/core/random_jkiss.c index feb0aa19a..f60b4beee 100644 --- a/server/core/random_jkiss.c +++ b/server/core/random_jkiss.c @@ -117,11 +117,13 @@ static void random_init_jkiss(void) { int newrand, i; + spinlock_acquire(&random_jkiss_spinlock); if ((newrand = random_jkiss_devrand()) != 0) x = newrand; if ((newrand = random_jkiss_devrand()) != 0) y = newrand; if ((newrand = random_jkiss_devrand()) != 0) z = newrand; if ((newrand = random_jkiss_devrand()) != 0) c = newrand % 698769068 + 1; /* Should be less than 698769069 */ + spinlock_release(&random_jkiss_spinlock); /* "Warm up" our random number generator */ for (i = 0; i < 100; i++) random_jkiss(); diff --git a/server/core/session.c b/server/core/session.c index 31bbbd637..b50d5e0c8 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -56,6 +56,7 @@ static size_t session_id; static SPINLOCK session_spin = SPINLOCK_INIT; static SESSION *allSessions = NULL; +static struct session session_dummy_struct; static int session_setup_filters(SESSION *session); static void session_simple_free(SESSION *session, DCB *dcb); @@ -212,6 +213,48 @@ session_alloc(SERVICE *service, DCB *client_dcb) return session; } +/** + * Allocate a dummy session so that DCBs can always have sessions. + * + * Only one dummy session exists, it is statically declared + * + * @param client_dcb The client side DCB + * @return The dummy created session + */ +SESSION * +session_alloc_dummy(DCB *client_dcb) +{ + SESSION *session; + + session = &session_dummy_struct; +#if defined(SS_DEBUG) + session->ses_chk_top = CHK_NUM_SESSION; + session->ses_chk_tail = CHK_NUM_SESSION; +#endif + session->ses_is_child = false; + spinlock_init(&session->ses_lock); + session->service = NULL; + session->client = NULL; + session->n_filters = 0; + memset(&session->stats, 0, sizeof(SESSION_STATS)); + session->stats.connect = 0; + session->state = SESSION_STATE_DUMMY; + /*< + * Associate the session to the client DCB and set the reference count on + * the session to indicate that there is a single reference to the + * session. There is no need to protect this or use atomic add as the + * session has not been made available to the other threads at this + * point. + */ + session->data = NULL; + session->refcount = 1; + session->ses_id = 0; + session->next = NULL; + + client_dcb->session = session; + return session; +} + /** * Enable specified logging for the current session and increase logger * counter. @@ -323,6 +366,10 @@ session_simple_free(SESSION *session, DCB *dcb) } if (session) { + if (SESSION_STATE_DUMMY == session->state) + { + return; + } if (session && session->router_session) { session->service->router->freeSession( @@ -344,6 +391,10 @@ session_simple_free(SESSION *session, DCB *dcb) bool session_free(SESSION *session) { + if (session && SESSION_STATE_DUMMY == session->state) + { + return true; + } CHK_SESSION(session); /* @@ -711,6 +762,8 @@ session_state(int state) { case SESSION_STATE_ALLOC: return "Session Allocated"; + case SESSION_STATE_DUMMY: + return "Dummy Session"; case SESSION_STATE_READY: return "Session Ready"; case SESSION_STATE_ROUTER_READY: diff --git a/server/include/session.h b/server/include/session.h index 7a9381507..e916c902e 100644 --- a/server/include/session.h +++ b/server/include/session.h @@ -64,7 +64,8 @@ typedef enum { SESSION_STATE_LISTENER, /*< for listener session */ SESSION_STATE_LISTENER_STOPPED, /*< for listener session */ SESSION_STATE_TO_BE_FREED, /*< ready to be freed as soon as there are no references */ - SESSION_STATE_FREE /*< for all sessions */ + SESSION_STATE_FREE, /*< for all sessions */ + SESSION_STATE_DUMMY /*< dummy session for consistency */ } session_state_t; /** @@ -162,6 +163,7 @@ typedef struct session { SESSION *get_all_sessions(); SESSION *session_alloc(struct service *, struct dcb *); +SESSION *session_alloc_dummy(struct dcb *); bool session_free(SESSION *); int session_isvalid(SESSION *); int session_reply(void *inst, void *session, GWBUF *data); diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index de178fe60..6a024c348 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -140,7 +140,7 @@ static MYSQL_session* gw_get_shared_session_auth_info( spinlock_acquire(&dcb->session->ses_lock); - if (dcb->session->state != SESSION_STATE_ALLOC) { + if (dcb->session->state != SESSION_STATE_ALLOC && dcb->session->state != SESSION_STATE_DUMMY) { auth_info = dcb->session->data; } else { LOGIF(LE, (skygw_log_write_flush( diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index 70ddcac84..33515c89b 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -912,7 +912,7 @@ int gw_read_client_event( if (session != NULL) { CHK_SESSION(session); - ss_dassert(session->state != SESSION_STATE_ALLOC); + ss_dassert(session->state != SESSION_STATE_ALLOC && session->state != SESSION_STATE_DUMMY); protocol->protocol_auth_state = MYSQL_IDLE; /** @@ -1012,7 +1012,7 @@ int gw_read_client_event( if (session != NULL) { CHK_SESSION(session); - ss_dassert(session->state != SESSION_STATE_ALLOC); + ss_dassert(session->state != SESSION_STATE_ALLOC && session->state != SESSION_STATE_DUMMY); protocol->protocol_auth_state = MYSQL_IDLE; /** @@ -1643,6 +1643,7 @@ int gw_MySQLAccept(DCB *listener) } client_dcb->service = listener->session->service; + client_dcb->session = session_alloc_dummy(client_dcb); client_dcb->fd = c_sock; // get client address diff --git a/utils/skygw_debug.h b/utils/skygw_debug.h index ff5d5c9c0..8f164b828 100644 --- a/utils/skygw_debug.h +++ b/utils/skygw_debug.h @@ -210,10 +210,11 @@ typedef enum skygw_chk_t { ((s) == DCB_STATE_UNDEFINED ? "DCB_STATE_UNDEFINED" : "DCB_STATE_UNKNOWN"))))))) #define STRSESSIONSTATE(s) ((s) == SESSION_STATE_ALLOC ? "SESSION_STATE_ALLOC" : \ - ((s) == SESSION_STATE_READY ? "SESSION_STATE_READY" : \ - ((s) == SESSION_STATE_LISTENER ? "SESSION_STATE_LISTENER" : \ - ((s) == SESSION_STATE_LISTENER_STOPPED ? "SESSION_STATE_LISTENER_STOPPED" : \ - (s) == SESSION_STATE_ROUTER_READY ? "SESSION_STATE_ROUTER_READY":\ + ((s) == SESSION_STATE_DUMMY ? "SESSION_STATE_DUMMY" : \ + ((s) == SESSION_STATE_READY ? "SESSION_STATE_READY" : \ + ((s) == SESSION_STATE_LISTENER ? "SESSION_STATE_LISTENER" : \ + ((s) == SESSION_STATE_LISTENER_STOPPED ? "SESSION_STATE_LISTENER_STOPPED" : \ + (s) == SESSION_STATE_ROUTER_READY ? "SESSION_STATE_ROUTER_READY":\ "SESSION_STATE_UNKNOWN")))) #define STRPROTOCOLSTATE(s) ((s) == MYSQL_ALLOC ? "MYSQL_ALLOC" : \