MXS-2196: Split session startup into two parts

The session allocation now has two distinct parts: the initialization of
the session itself and the creation of the router and filter
sessions. This allows sessions to be allocated the moment a client DCB is
created instead of only after the authentication is complete. With this
change, the need for the dummy session is removed.
This commit is contained in:
Markus Mäkelä 2018-12-03 08:45:00 +02:00
parent 13769a0e8c
commit 180e150ba1
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
2 changed files with 65 additions and 80 deletions

View File

@ -303,6 +303,19 @@ MXS_SESSION* session_alloc(SERVICE*, DCB*);
*/
MXS_SESSION* session_alloc_with_id(SERVICE*, DCB*, uint64_t);
/**
* Start the session
*
* Called after the session is initialized and authentication is complete. This creates the router and filter
* sessions.
*
* @param session Session to start
* @param service The service where the session is started
*
* @return True if session was started successfully
*/
bool session_start(MXS_SESSION* session, SERVICE* service);
MXS_SESSION* session_set_dummy(DCB*);
static inline bool session_is_dummy(MXS_SESSION* session)

View File

@ -158,96 +158,68 @@ static MXS_SESSION* session_alloc_body(SERVICE* service,
memset(&session->response, 0, sizeof(session->response));
session->close_reason = SESSION_CLOSE_NONE;
if (client_dcb->dcb_role != DCB_ROLE_INTERNAL && !session_start(session, service))
{
// The session will be freed when the client DCB is freed
session = nullptr;
}
return session;
}
bool session_start(MXS_SESSION* session, SERVICE* service)
{
session->router_session = service->router->newSession(service->router_instance, session);
if (session->router_session == NULL)
{
session->state = SESSION_STATE_TO_BE_FREED;
MXS_ERROR("Failed to create new router session for service '%s'. "
"See previous errors for more details.", service->name);
return false;
}
/*
* Only create a router session if we are not the listening DCB or an
* internal DCB. Creating a router session may create a connection to
* a backend server, depending upon the router module implementation
* and should be avoided for a listener session.
* Pending filter chain being setup set the head of the chain to
* be the router. As filters are inserted the current head will
* be pushed to the filter and the head updated.
*
* Router session creation may create other DCBs that link to the
* session.
* NB This dictates that filters are created starting at the end
* of the chain nearest the router working back to the client
* protocol end of the chain.
*/
if (client_dcb->state != DCB_STATE_LISTENING
&& client_dcb->dcb_role != DCB_ROLE_INTERNAL)
// NOTE: Here we cast the router instance into a MXS_FILTER and
// NOTE: the router session into a MXS_FILTER_SESSION and
// NOTE: the router routeQuery into a filter routeQuery. That
// NOTE: is in order to be able to treat the router as the first
// NOTE: filter.
session->head = router_as_downstream(session);
// NOTE: Here we cast the session into a MXS_FILTER and MXS_FILTER_SESSION
// NOTE: and session_reply into a filter clientReply. That's dubious but ok
// NOTE: as session_reply will know what to do. In practice, the session
// NOTE: will be called as if it would be the last filter.
session->tail.instance = (MXS_FILTER*)session;
session->tail.session = (MXS_FILTER_SESSION*)session;
session->tail.clientReply = session_reply;
if (!session_setup_filters(session))
{
session->router_session = service->router->newSession(service->router_instance, session);
if (session->router_session == NULL)
{
session->state = SESSION_STATE_TO_BE_FREED;
MXS_ERROR("Failed to create new router session for service '%s'. "
"See previous errors for more details.",
service->name);
}
/*
* Pending filter chain being setup set the head of the chain to
* be the router. As filters are inserted the current head will
* be pushed to the filter and the head updated.
*
* NB This dictates that filters are created starting at the end
* of the chain nearest the router working back to the client
* protocol end of the chain.
*/
// NOTE: Here we cast the router instance into a MXS_FILTER and
// NOTE: the router session into a MXS_FILTER_SESSION and
// NOTE: the router routeQuery into a filter routeQuery. That
// NOTE: is in order to be able to treat the router as the first
// NOTE: filter.
session->head = router_as_downstream(session);
// NOTE: Here we cast the session into a MXS_FILTER and MXS_FILTER_SESSION
// NOTE: and session_reply into a filter clientReply. That's dubious but ok
// NOTE: as session_reply will know what to do. In practice, the session
// NOTE: will be called as if it would be the last filter.
session->tail.instance = (MXS_FILTER*)session;
session->tail.session = (MXS_FILTER_SESSION*)session;
session->tail.clientReply = session_reply;
if (SESSION_STATE_TO_BE_FREED != session->state
&& !session_setup_filters(session))
{
session->state = SESSION_STATE_TO_BE_FREED;
MXS_ERROR("Setting up filters failed. "
"Terminating session %s.",
service->name);
}
session->state = SESSION_STATE_TO_BE_FREED;
MXS_ERROR("Setting up filters failed. Terminating session %s.", session->service->name);
return false;
}
if (SESSION_STATE_TO_BE_FREED != session->state)
{
session->state = SESSION_STATE_ROUTER_READY;
if (session->client_dcb->user == NULL)
{
MXS_INFO("Started session [%" PRIu64 "] for %s service ",
session->ses_id,
service->name);
}
else
{
MXS_INFO("Started %s client session [%" PRIu64 "] for '%s' from %s",
service->name,
session->ses_id,
session->client_dcb->user,
session->client_dcb->remote);
}
}
else
{
MXS_INFO("Start %s client session [%" PRIu64 "] for '%s' from %s failed, will be "
"closed as soon as all related DCBs have been closed.",
service->name,
session->ses_id,
session->client_dcb->user,
session->client_dcb->remote);
}
session->state = SESSION_STATE_ROUTER_READY;
mxb::atomic::add(&service->stats.n_sessions, 1, mxb::atomic::RELAXED);
mxb::atomic::add(&service->stats.n_current, 1, mxb::atomic::RELAXED);
// Store the session in the client DCB even if the session creation fails.
// It will be freed later on when the DCB is closed.
client_dcb->session = session;
MXS_INFO("Started %s client session [%" PRIu64 "] for '%s' from %s",
service->name, session->ses_id,
session->client_dcb->user ? session->client_dcb->user : "<no user>",
session->client_dcb->remote);
return (session->state == SESSION_STATE_TO_BE_FREED) ? NULL : session;
return true;
}
/**