Add check so DCB can't be added to poll list without a linked session; small safety improvement in session; tidying.
This commit is contained in:
@ -74,6 +74,8 @@ int max_poll_sleep;
|
|||||||
* thread utilisation and fairer scheduling of the event
|
* thread utilisation and fairer scheduling of the event
|
||||||
* processing.
|
* processing.
|
||||||
* 07/07/15 Martin Brampton Simplified add and remove DCB, improve error handling.
|
* 07/07/15 Martin Brampton Simplified add and remove DCB, improve error handling.
|
||||||
|
* 23/08/15 Martin Brampton Provisionally added test so only DCB with a
|
||||||
|
* session link can be added to the poll list
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -254,12 +256,12 @@ int i;
|
|||||||
int
|
int
|
||||||
poll_add_dcb(DCB *dcb)
|
poll_add_dcb(DCB *dcb)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
dcb_state_t old_state = dcb->state;
|
dcb_state_t old_state = dcb->state;
|
||||||
dcb_state_t new_state;
|
dcb_state_t new_state;
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
|
|
||||||
#ifdef EPOLLRDHUP
|
#ifdef EPOLLRDHUP
|
||||||
ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET;
|
ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET;
|
||||||
@ -268,65 +270,86 @@ poll_add_dcb(DCB *dcb)
|
|||||||
#endif
|
#endif
|
||||||
ev.data.ptr = dcb;
|
ev.data.ptr = dcb;
|
||||||
|
|
||||||
/*<
|
/*<
|
||||||
* Choose new state according to the role of dcb.
|
* Choose new state according to the role of dcb.
|
||||||
*/
|
*/
|
||||||
spinlock_acquire(&dcb->dcb_initlock);
|
spinlock_acquire(&dcb->dcb_initlock);
|
||||||
if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) {
|
if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER)
|
||||||
new_state = DCB_STATE_POLLING;
|
{
|
||||||
} else {
|
new_state = DCB_STATE_POLLING;
|
||||||
ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER);
|
}
|
||||||
new_state = DCB_STATE_LISTENING;
|
else
|
||||||
}
|
{
|
||||||
/*
|
ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER);
|
||||||
* Check DCB current state seems sensible
|
new_state = DCB_STATE_LISTENING;
|
||||||
*/
|
}
|
||||||
if (DCB_STATE_DISCONNECTED == dcb->state
|
/*
|
||||||
|| DCB_STATE_ZOMBIE == dcb->state
|
* Check DCB current state seems sensible
|
||||||
|| DCB_STATE_UNDEFINED == dcb->state)
|
*/
|
||||||
{
|
if (DCB_STATE_DISCONNECTED == dcb->state
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
|| DCB_STATE_ZOMBIE == dcb->state
|
||||||
LOGFILE_ERROR,
|
|| DCB_STATE_UNDEFINED == dcb->state)
|
||||||
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
{
|
||||||
"is %s, but this should be impossible, crashing.",
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
pthread_self(),
|
LOGFILE_ERROR,
|
||||||
dcb,
|
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
||||||
STRDCBSTATE(dcb->state))));
|
"is %s, but this should be impossible, crashing.",
|
||||||
raise(SIGABRT);
|
pthread_self(),
|
||||||
}
|
dcb,
|
||||||
if (DCB_STATE_POLLING == dcb->state
|
STRDCBSTATE(dcb->state))));
|
||||||
|| DCB_STATE_LISTENING == dcb->state)
|
raise(SIGABRT);
|
||||||
{
|
}
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
/*
|
||||||
LOGFILE_ERROR,
|
* This test could be wrong. On the face of it, we don't want to add a
|
||||||
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
* DCB to the poll list if it is not linked to a session because the code
|
||||||
"is %s, but this is probably an error, not crashing.",
|
* that handles events will expect to find a session. Test added by
|
||||||
pthread_self(),
|
* Martin as an experiment on 23 August 2015
|
||||||
dcb,
|
*/
|
||||||
STRDCBSTATE(dcb->state))));
|
if (NULL == dcb->session)
|
||||||
}
|
{
|
||||||
dcb->state = new_state;
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
spinlock_release(&dcb->dcb_initlock);
|
LOGFILE_ERROR,
|
||||||
/*
|
"%lu [%s] Error : Attempt to add dcb %p "
|
||||||
* The only possible failure that will not cause a crash is
|
"to poll list but it is not linked to a session, crashing.",
|
||||||
* running out of system resources.
|
__func__,
|
||||||
*/
|
pthread_self(),
|
||||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
|
dcb)));
|
||||||
if (rc)
|
raise(SIGABRT);
|
||||||
{
|
}
|
||||||
rc = poll_resolve_error(dcb, errno, true);
|
if (DCB_STATE_POLLING == dcb->state
|
||||||
}
|
|| DCB_STATE_LISTENING == dcb->state)
|
||||||
if (0 == rc)
|
{
|
||||||
{
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGFILE_ERROR,
|
||||||
LOGFILE_DEBUG,
|
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
||||||
"%lu [poll_add_dcb] Added dcb %p in state %s to poll set.",
|
"is %s, but this is probably an error, not crashing.",
|
||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb,
|
dcb,
|
||||||
STRDCBSTATE(dcb->state))));
|
STRDCBSTATE(dcb->state))));
|
||||||
}
|
}
|
||||||
else dcb->state = old_state;
|
dcb->state = new_state;
|
||||||
return rc;
|
spinlock_release(&dcb->dcb_initlock);
|
||||||
|
/*
|
||||||
|
* The only possible failure that will not cause a crash is
|
||||||
|
* running out of system resources.
|
||||||
|
*/
|
||||||
|
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
/* Some errors are actually considered acceptable */
|
||||||
|
rc = poll_resolve_error(dcb, errno, true);
|
||||||
|
}
|
||||||
|
if (0 == rc)
|
||||||
|
{
|
||||||
|
LOGIF(LD, (skygw_log_write(
|
||||||
|
LOGFILE_DEBUG,
|
||||||
|
"%lu [poll_add_dcb] Added dcb %p in state %s to poll set.",
|
||||||
|
pthread_self(),
|
||||||
|
dcb,
|
||||||
|
STRDCBSTATE(dcb->state))));
|
||||||
|
}
|
||||||
|
else dcb->state = old_state;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
* 17/06/13 Mark Riddoch Initial implementation
|
* 17/06/13 Mark Riddoch Initial implementation
|
||||||
* 02/09/13 Massimiliano Pinto Added session refcounter
|
* 02/09/13 Massimiliano Pinto Added session refcounter
|
||||||
* 29/05/14 Mark Riddoch Addition of filter mechanism
|
* 29/05/14 Mark Riddoch Addition of filter mechanism
|
||||||
|
* 23/08/15 Martin Brampton Tidying; slight improvement in safety
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -72,65 +73,66 @@ static int session_setup_filters(SESSION *session);
|
|||||||
SESSION *
|
SESSION *
|
||||||
session_alloc(SERVICE *service, DCB *client_dcb)
|
session_alloc(SERVICE *service, DCB *client_dcb)
|
||||||
{
|
{
|
||||||
SESSION *session;
|
SESSION *session;
|
||||||
|
|
||||||
session = (SESSION *)calloc(1, sizeof(SESSION));
|
session = (SESSION *)calloc(1, sizeof(SESSION));
|
||||||
ss_info_dassert(session != NULL,
|
ss_info_dassert(session != NULL,
|
||||||
"Allocating memory for session failed.");
|
"Allocating memory for session failed.");
|
||||||
|
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
{
|
{
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Failed to allocate memory for "
|
"Error : Failed to allocate memory for "
|
||||||
"session object due error %d, %s.",
|
"session object due error %d, %s.",
|
||||||
errno,
|
errno,
|
||||||
strerror(errno))));
|
strerror(errno))));
|
||||||
if (client_dcb->data && !DCB_IS_CLONE(client_dcb))
|
if (client_dcb->data && !DCB_IS_CLONE(client_dcb))
|
||||||
{
|
{
|
||||||
free(client_dcb->data);
|
void *clientdata = client_dcb->data;
|
||||||
client_dcb->data = NULL;
|
client_dcb->data = NULL;
|
||||||
}
|
free(clientdata);
|
||||||
goto return_session;
|
|
||||||
}
|
}
|
||||||
|
goto return_session;
|
||||||
|
}
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
session->ses_chk_top = CHK_NUM_SESSION;
|
session->ses_chk_top = CHK_NUM_SESSION;
|
||||||
session->ses_chk_tail = CHK_NUM_SESSION;
|
session->ses_chk_tail = CHK_NUM_SESSION;
|
||||||
#endif
|
#endif
|
||||||
if (DCB_IS_CLONE(client_dcb))
|
if (DCB_IS_CLONE(client_dcb))
|
||||||
{
|
{
|
||||||
session->ses_is_child = true;
|
session->ses_is_child = true;
|
||||||
}
|
}
|
||||||
spinlock_init(&session->ses_lock);
|
spinlock_init(&session->ses_lock);
|
||||||
/*<
|
/*<
|
||||||
* Prevent backend threads from accessing before session is completely
|
* Prevent backend threads from accessing before session is completely
|
||||||
* initialized.
|
* initialized.
|
||||||
*/
|
*/
|
||||||
spinlock_acquire(&session->ses_lock);
|
spinlock_acquire(&session->ses_lock);
|
||||||
session->service = service;
|
session->service = service;
|
||||||
session->client = client_dcb;
|
session->client = client_dcb;
|
||||||
session->n_filters = 0;
|
session->n_filters = 0;
|
||||||
memset(&session->stats, 0, sizeof(SESSION_STATS));
|
memset(&session->stats, 0, sizeof(SESSION_STATS));
|
||||||
session->stats.connect = time(0);
|
session->stats.connect = time(0);
|
||||||
session->state = SESSION_STATE_ALLOC;
|
session->state = SESSION_STATE_ALLOC;
|
||||||
/*<
|
/*<
|
||||||
* Associate the session to the client DCB and set the reference count on
|
* 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
|
* 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. 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
|
* session has not been made available to the other threads at this
|
||||||
* point.
|
* point.
|
||||||
*/
|
*/
|
||||||
session->data = client_dcb->data;
|
session->data = client_dcb->data;
|
||||||
client_dcb->session = session;
|
client_dcb->session = session;
|
||||||
session->refcount = 1;
|
session->refcount = 1;
|
||||||
/*<
|
/*<
|
||||||
* This indicates that session is ready to be shared with backend
|
* This indicates that session is ready to be shared with backend
|
||||||
* DCBs. Note that this doesn't mean that router is initialized yet!
|
* DCBs. Note that this doesn't mean that router is initialized yet!
|
||||||
*/
|
*/
|
||||||
session->state = SESSION_STATE_READY;
|
session->state = SESSION_STATE_READY;
|
||||||
|
|
||||||
/*< Release session lock */
|
/*< Release session lock */
|
||||||
spinlock_release(&session->ses_lock);
|
spinlock_release(&session->ses_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only create a router session if we are not the listening
|
* Only create a router session if we are not the listening
|
||||||
@ -140,36 +142,34 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
*
|
*
|
||||||
* Router session creation may create other DCBs that link to the
|
* Router session creation may create other DCBs that link to the
|
||||||
* session, therefore it is important that the session lock is
|
* session, therefore it is important that the session lock is
|
||||||
* relinquished beforethe router call.
|
* relinquished before the router call.
|
||||||
*/
|
*/
|
||||||
if (client_dcb->state != DCB_STATE_LISTENING &&
|
if (client_dcb->state != DCB_STATE_LISTENING &&
|
||||||
client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
||||||
{
|
{
|
||||||
session->router_session =
|
session->router_session =
|
||||||
service->router->newSession(service->router_instance,
|
service->router->newSession(service->router_instance, session);
|
||||||
session);
|
if (session->router_session == NULL)
|
||||||
|
|
||||||
if (session->router_session == NULL)
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Inform other threads that session is closing.
|
* Inform other threads that session is closing.
|
||||||
*/
|
*/
|
||||||
session->state = SESSION_STATE_STOPPING;
|
session->state = SESSION_STATE_STOPPING;
|
||||||
/*<
|
/*<
|
||||||
* Decrease refcount, set dcb's session pointer NULL
|
* Decrease refcount, set dcb's session pointer NULL
|
||||||
* and set session pointer to NULL.
|
* and set session pointer to NULL.
|
||||||
*/
|
*/
|
||||||
session->client = NULL;
|
session->client = NULL;
|
||||||
session_free(session);
|
session_free(session);
|
||||||
client_dcb->session = NULL;
|
client_dcb->session = NULL;
|
||||||
session = NULL;
|
session = NULL;
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Failed to create %s session.",
|
"Error : Failed to create %s session.",
|
||||||
service->name)));
|
service->name)));
|
||||||
|
|
||||||
goto return_session;
|
goto return_session;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Pending filter chain being setup set the head of the chain to
|
* Pending filter chain being setup set the head of the chain to
|
||||||
* be the router. As filters are inserted the current head will
|
* be the router. As filters are inserted the current head will
|
||||||
|
|||||||
Reference in New Issue
Block a user