diff --git a/include/maxscale/dcb.h b/include/maxscale/dcb.h index 4b39d4b9c..2f4797de5 100644 --- a/include/maxscale/dcb.h +++ b/include/maxscale/dcb.h @@ -377,6 +377,8 @@ int dcb_accept_SSL(DCB* dcb); int dcb_connect_SSL(DCB* dcb); int dcb_listen(DCB *listener, const char *config, const char *protocol_name); void dcb_append_readqueue(DCB *dcb, GWBUF *buffer); +void dcb_enable_session_timeouts(); +void dcb_process_idle_sessions(int thr); /** * DCB flags values diff --git a/include/maxscale/session.h b/include/maxscale/session.h index 855e922ca..66e15fed7 100644 --- a/include/maxscale/session.h +++ b/include/maxscale/session.h @@ -185,13 +185,6 @@ typedef struct session .stats = SESSION_STATS_INIT, .head = DOWNSTREAM_INIT, .tail = UPSTREAM_INIT, \ .state = SESSION_STATE_ALLOC, .ses_chk_tail = CHK_NUM_SESSION} -/** Whether to do session timeout checks */ -extern bool check_timeouts; - -/** When the next timeout check is done. This is compared to hkheartbeat in - * hk_heartbeat.h */ -extern long next_timeout_check; - #define SESSION_PROTOCOL(x, type) DCB_PROTOCOL((x)->client_dcb, type) /** @@ -231,8 +224,6 @@ SESSION* get_session_by_router_ses(void* rses); void session_enable_log_priority(SESSION* ses, int priority); void session_disable_log_priority(SESSION* ses, int priority); RESULTSET *sessionGetList(SESSIONLISTFILTER); -void process_idle_sessions(); -void enable_session_timeouts(); /** * Get the transaction state of the session. diff --git a/server/core/dcb.c b/server/core/dcb.c index 471e9df08..c02cefc8b 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -92,6 +92,7 @@ #include #include #include +#include /* The list of all DCBs */ static LIST_CONFIG DCBlist = @@ -107,6 +108,10 @@ static int *nzombies; static int maxzombies = 0; static SPINLOCK zombiespin = SPINLOCK_INIT; +/** Variables for session timeout checks */ +bool check_timeouts = false; +thread_local long next_timeout_check = 0; + void dcb_global_init() { int nthreads = config_threadcount(); @@ -3479,3 +3484,41 @@ static void dcb_remove_from_list(DCB *dcb) spinlock_release(&all_dcbs_lock[dcb->owner]); } + +/** + * Enable the timing out of idle connections. + */ +void dcb_enable_session_timeouts() +{ + check_timeouts = true; +} + +/** + * Close sessions that have been idle for too long. + * + * If the time since a session last sent data is greater than the set value in the + * service, it is disconnected. The connection timeout is disabled by default. + */ +void dcb_process_idle_sessions(int thr) +{ + if (check_timeouts && hkheartbeat >= next_timeout_check) + { + /** Because the resolution of the timeout is one second, we only need to + * check for it once per second. One heartbeat is 100 milliseconds. */ + next_timeout_check = hkheartbeat + 10; + + for (DCB *dcb = all_dcbs[thr]; dcb; dcb = dcb->memdata.next) + { + if (dcb->dcb_role == DCB_ROLE_CLIENT_HANDLER) + { + SESSION *session = dcb->session; + + if (session->service && session->client_dcb && session->client_dcb->state == DCB_STATE_POLLING && + hkheartbeat - session->client_dcb->last_read > session->service->conn_idle_timeout * 10) + { + poll_fake_hangup_event(dcb); + } + } + } + } +} diff --git a/server/core/poll.c b/server/core/poll.c index 0955ba20f..b77f59304 100644 --- a/server/core/poll.c +++ b/server/core/poll.c @@ -752,10 +752,7 @@ poll_waitevents(void *arg) MXS_FREE(tmp); } - if (check_timeouts && hkheartbeat >= next_timeout_check) - { - process_idle_sessions(); - } + dcb_process_idle_sessions(thread_id); if (thread_data) { diff --git a/server/core/service.c b/server/core/service.c index 381f95d79..0c7165e64 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -1052,7 +1052,7 @@ serviceSetTimeout(SERVICE *service, int val) * configured with a idle timeout. */ if ((service->conn_idle_timeout = val)) { - enable_session_timeouts(); + dcb_enable_session_timeouts(); } return 1; diff --git a/server/core/session.c b/server/core/session.c index 87baf1f01..38bcbd8b3 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -56,14 +56,6 @@ static int session_id; static struct session session_dummy_struct; -/** - * These two are declared in session.h - */ -bool check_timeouts = false; -long next_timeout_check = 0; - -static SPINLOCK timeout_lock = SPINLOCK_INIT; - static void session_initialize(void *session); static int session_setup_filters(SESSION *session); static void session_simple_free(SESSION *session, DCB *dcb); @@ -894,50 +886,6 @@ session_getUser(SESSION *session) return (session && session->client_dcb) ? session->client_dcb->user : NULL; } -/** - * Enable the timing out of idle connections. - * - * This will prevent unnecessary acquisitions of the session spinlock if no - * service is configured with a session idle timeout. - */ -void enable_session_timeouts() -{ - check_timeouts = true; -} - -/** - * Close sessions that have been idle for too long. - * - * If the time since a session last sent data is greater than the set value in the - * service, it is disconnected. The connection timeout is disabled by default. - */ -void process_idle_sessions() -{ - if (spinlock_acquire_nowait(&timeout_lock)) - { - if (hkheartbeat >= next_timeout_check) - { - list_entry_t *current = list_start_iteration(&SESSIONlist); - /** Because the resolution of the timeout is one second, we only need to - * check for it once per second. One heartbeat is 100 milliseconds. */ - next_timeout_check = hkheartbeat + 10; - while (current) - { - SESSION *all_session = (SESSION *)current; - - if (all_session->service && all_session->client_dcb && all_session->client_dcb->state == DCB_STATE_POLLING && - hkheartbeat - all_session->client_dcb->last_read > all_session->service->conn_idle_timeout * 10) - { - poll_fake_hangup_event(all_session->client_dcb); - } - - current = list_iterate(&SESSIONlist, current); - } - } - spinlock_release(&timeout_lock); - } -} - /** * Callback structure for the session list extraction */