Adapt session timeout checks to a per thread model

Each thread will now check their own list of DCBs for timed out sessions.
This commit is contained in:
Markus Makela 2016-11-20 10:34:37 +02:00
parent 30927455ef
commit 5067f3594a
6 changed files with 47 additions and 66 deletions

View File

@ -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

View File

@ -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.

View File

@ -92,6 +92,7 @@
#include <sys/un.h>
#include <maxscale/alloc.h>
#include <maxscale/utils.h>
#include <maxscale/platform.h>
/* 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);
}
}
}
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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
*/