diff --git a/server/core/session.c b/server/core/session.c index f48e6872d..cb72ea0bd 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -31,12 +31,16 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include + static SPINLOCK session_spin = SPINLOCK_INIT; static SESSION *allSessions = NULL; @@ -55,18 +59,40 @@ static SESSION *allSessions = NULL; SESSION * session_alloc(SERVICE *service, DCB *client) { -SESSION *session; + SESSION *session; - if ((session = (SESSION *)malloc(sizeof(SESSION))) == NULL) + session = (SESSION *)calloc(1, sizeof(SESSION)); + + if (session == NULL) { + int eno = errno; + errno = 0; + skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [session_alloc] Allocating memory for session " + "object failed. Errno %d, %s.", + pthread_self(), + eno, + strerror(eno)); return NULL; + } + session->ses_chk_top = CHK_NUM_SESSION; + session->ses_chk_tail = CHK_NUM_SESSION; spinlock_init(&session->ses_lock); - session->service = service; + /** + * Prevent backend threads from accessing before session is completely + * initialized. + */ + spinlock_acquire(&session->ses_lock); + session->service = service; session->client = client; memset(&session->stats, 0, sizeof(SESSION_STATS)); session->stats.connect = time(0); session->state = SESSION_STATE_ALLOC; + /** + * If client has data pointer to authentication info, set it to session. + */ + session->data = client->data; client->session = session; - /* * Only create a router session if we are not the listening * DCB. Creating a router session may create a connection to a @@ -75,17 +101,22 @@ SESSION *session; */ if (client->state != DCB_STATE_LISTENING) { - session->router_session = service->router->newSession(service->router_instance, session); + session->router_session = + service->router->newSession(service->router_instance, session); } - spinlock_acquire(&session_spin); session->next = allSessions; allSessions = session; spinlock_release(&session_spin); + /** This indicates that session is ready to be shared with backend DCBs. */ + session->state = SESSION_STATE_READY; + /** Release session lock */ + spinlock_release(&session->ses_lock); + atomic_add(&service->stats.n_sessions, 1); atomic_add(&service->stats.n_current, 1); - + CHK_SESSION(session); return session; } @@ -98,8 +129,9 @@ void session_free(SESSION *session) { SESSION *ptr; - + CHK_SESSION(session); /* First of all remove from the linked list */ + spinlock_acquire(&session_spin); if (allSessions == session) { @@ -117,7 +149,6 @@ SESSION *ptr; } spinlock_release(&session_spin); atomic_add(&session->service->stats.n_current, -1); - /* Clean up session and free the memory */ free(session); } diff --git a/server/include/session.h b/server/include/session.h index c91b837bd..e0de9a303 100644 --- a/server/include/session.h +++ b/server/include/session.h @@ -35,6 +35,7 @@ #include #include #include +#include struct dcb; struct service; @@ -46,6 +47,21 @@ typedef struct { time_t connect; /**< Time when the session was started */ } SESSION_STATS; + +#if 0 +#define SESSION_STATE_ALLOC 0 /**< The session has been allocated */ +#define SESSION_STATE_READY 1 /**< The session is ready to route queries */ +#define SESSION_STATE_LISTENER 2 /**< The session is a running listener */ +#define SESSION_STATE_LISTENER_STOPPED 3 /**< The session listener is stopped */ +#else +typedef enum { + SESSION_STATE_ALLOC, + SESSION_STATE_READY, + SESSION_STATE_LISTENER, + SESSION_STATE_LISTENER_STOPPED +} session_state_t; +#endif + /** * The session status block * @@ -54,8 +70,9 @@ typedef struct { * and originating service together for the client session. */ typedef struct session { + skygw_chk_t ses_chk_top; SPINLOCK ses_lock; - int state; /**< Current descriptor state */ + session_state_t state; /**< Current descriptor state */ struct dcb *client; /**< The client connection */ struct dcb *backends; /**< The set of backend servers */ void *data; /**< The session data */ @@ -63,13 +80,9 @@ typedef struct session { SESSION_STATS stats; /**< Session statistics */ struct service *service; /**< The service this session is using */ struct session *next; /**< Linked list of all sessions */ + skygw_chk_t ses_chk_tail; } SESSION; -#define SESSION_STATE_ALLOC 0 /**< The session has been allocated */ -#define SESSION_STATE_READY 1 /**< The session is ready to route queries */ -#define SESSION_STATE_LISTENER 2 /**< The session is a running listener */ -#define SESSION_STATE_LISTENER_STOPPED 3 /**< The session listener is stopped */ - #define SESSION_PROTOCOL(x, type) DCB_PROTOCOL((x)->client, type) extern SESSION *session_alloc(struct service *, struct dcb *);