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:
@ -303,6 +303,19 @@ MXS_SESSION* session_alloc(SERVICE*, DCB*);
|
|||||||
*/
|
*/
|
||||||
MXS_SESSION* session_alloc_with_id(SERVICE*, DCB*, uint64_t);
|
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*);
|
MXS_SESSION* session_set_dummy(DCB*);
|
||||||
|
|
||||||
static inline bool session_is_dummy(MXS_SESSION* session)
|
static inline bool session_is_dummy(MXS_SESSION* session)
|
||||||
|
@ -158,96 +158,68 @@ static MXS_SESSION* session_alloc_body(SERVICE* service,
|
|||||||
memset(&session->response, 0, sizeof(session->response));
|
memset(&session->response, 0, sizeof(session->response));
|
||||||
session->close_reason = SESSION_CLOSE_NONE;
|
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
|
* Pending filter chain being setup set the head of the chain to
|
||||||
* internal DCB. Creating a router session may create a connection to
|
* be the router. As filters are inserted the current head will
|
||||||
* a backend server, depending upon the router module implementation
|
* be pushed to the filter and the head updated.
|
||||||
* and should be avoided for a listener session.
|
|
||||||
*
|
*
|
||||||
* Router session creation may create other DCBs that link to the
|
* NB This dictates that filters are created starting at the end
|
||||||
* session.
|
* of the chain nearest the router working back to the client
|
||||||
|
* protocol end of the chain.
|
||||||
*/
|
*/
|
||||||
if (client_dcb->state != DCB_STATE_LISTENING
|
// NOTE: Here we cast the router instance into a MXS_FILTER and
|
||||||
&& client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
// 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);
|
session->state = SESSION_STATE_TO_BE_FREED;
|
||||||
if (session->router_session == NULL)
|
MXS_ERROR("Setting up filters failed. Terminating session %s.", session->service->name);
|
||||||
{
|
return false;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SESSION_STATE_TO_BE_FREED != session->state)
|
session->state = SESSION_STATE_ROUTER_READY;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
mxb::atomic::add(&service->stats.n_sessions, 1, mxb::atomic::RELAXED);
|
mxb::atomic::add(&service->stats.n_sessions, 1, mxb::atomic::RELAXED);
|
||||||
mxb::atomic::add(&service->stats.n_current, 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.
|
MXS_INFO("Started %s client session [%" PRIu64 "] for '%s' from %s",
|
||||||
// It will be freed later on when the DCB is closed.
|
service->name, session->ses_id,
|
||||||
client_dcb->session = session;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user