예제 #1
0
파일: session.c 프로젝트: bigshuai/MaxScale
int session_unlink_dcb(SESSION* session,
                       DCB*     dcb)
{
    int nlink;

    CHK_SESSION(session);

    spinlock_acquire(&session->ses_lock);
    ss_dassert(session->refcount > 0);
    /*<
     * Remove dcb from session's router_client_session.
     */
    nlink = atomic_add(&session->refcount, -1);
    nlink -= 1;

    if (nlink == 0)
    {
        session->state = SESSION_STATE_TO_BE_FREED;
    }

    if (dcb != NULL)
    {
        if (session->client_dcb == dcb)
        {
            session->client_dcb = NULL;
        }
        dcb->session = NULL;
    }
    spinlock_release(&session->ses_lock);

    return nlink;
}
예제 #2
0
파일: tee.c 프로젝트: DBMSRmutl/MaxScale
/**
 * Close a session with the filter, this is the mechanism
 * by which a filter may cleanup data structure etc.
 * In the case of the tee filter we need to close down the
 * "branch" session.
 *
 * @param instance	The filter instance data
 * @param session	The session being closed
 */
static void
closeSession(FILTER *instance, void *session)
{
    TEE_SESSION *my_session = (TEE_SESSION *) session;
    ROUTER_OBJECT *router;
    void *router_instance, *rsession;
    SESSION *bsession;
#ifdef SS_DEBUG
    MXS_INFO("Tee close: %d", atomic_add(&debug_seq, 1));
#endif
    if (my_session->active)
    {

        if ((bsession = my_session->branch_session) != NULL)
        {
            CHK_SESSION(bsession);
            spinlock_acquire(&bsession->ses_lock);

            if (bsession->state != SESSION_STATE_STOPPING)
            {
                bsession->state = SESSION_STATE_STOPPING;
            }
            router = bsession->service->router;
            router_instance = bsession->service->router_instance;
            rsession = bsession->router_session;
            spinlock_release(&bsession->ses_lock);

            /** Close router session and all its connections */
            router->closeSession(router_instance, rsession);
        }
        /* No need to free the session, this is done as
         * a side effect of closing the client DCB of the
         * session.
         */

        if (my_session->waiting[PARENT])
        {
            if (my_session->command != 0x01 &&
                my_session->client_dcb &&
                my_session->client_dcb->state == DCB_STATE_POLLING)
            {
                MXS_INFO("Tee session closed mid-query.");
                GWBUF* errbuf = modutil_create_mysql_err_msg(1, 0, 1, "00000", "Session closed.");
                my_session->client_dcb->func.write(my_session->client_dcb, errbuf);
            }
        }


        my_session->active = 0;
    }
}
예제 #3
0
파일: session.c 프로젝트: bigshuai/MaxScale
/**
 * Allocate a new session for a new client of the specified service.
 *
 * Create the link to the router session by calling the newSession
 * entry point of the router using the router instance of the
 * service this session is part of.
 *
 * @param service       The service this connection was established by
 * @param client_dcb    The client side DCB
 * @return              The newly created session or NULL if an error occured
 */
SESSION *
session_alloc(SERVICE *service, DCB *client_dcb)
{
    SESSION *session;

    session = (SESSION *)calloc(1, sizeof(SESSION));
    ss_info_dassert(session != NULL, "Allocating memory for session failed.");

    if (session == NULL)
    {
        char errbuf[STRERROR_BUFLEN];
        MXS_ERROR("Failed to allocate memory for "
                  "session object due error %d, %s.",
                  errno,
                  strerror_r(errno, errbuf, sizeof(errbuf)));
        return NULL;
    }
#if defined(SS_DEBUG)
    session->ses_chk_top = CHK_NUM_SESSION;
    session->ses_chk_tail = CHK_NUM_SESSION;
#endif
    session->ses_is_child = (bool) DCB_IS_CLONE(client_dcb);
    spinlock_init(&session->ses_lock);
    session->service = service;
    session->client_dcb = client_dcb;
    session->n_filters = 0;
    memset(&session->stats, 0, sizeof(SESSION_STATS));
    session->stats.connect = time(0);
    session->state = SESSION_STATE_ALLOC;
    /*<
     * 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
     * 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
     * point.
     */
    session->refcount = 1;
    /*<
     * This indicates that session is ready to be shared with backend
     * DCBs. Note that this doesn't mean that router is initialized yet!
     */
    session->state = SESSION_STATE_READY;

    /*
     * 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 the listener session
     *
     * Router session creation may create other DCBs that link to the
     * session, therefore it is important that the session lock is
     * relinquished before the router call.
     */
    if (client_dcb->state != DCB_STATE_LISTENING &&
        client_dcb->dcb_role != DCB_ROLE_INTERNAL)
    {
        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.
         */
        session->head.instance = service->router_instance;
        session->head.session = session->router_session;

        session->head.routeQuery = (void *)(service->router->routeQuery);

        session->tail.instance = session;
        session->tail.session = session;
        session->tail.clientReply = session_reply;

        if (SESSION_STATE_TO_BE_FREED != session->state
            && service->n_filters > 0
            && !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;

        if (session->client_dcb->user == NULL)
        {
            MXS_INFO("Started session [%lu] for %s service ",
                     session->ses_id,
                     service->name);
        }
        else
        {
            MXS_INFO("Started %s client session [%lu] for '%s' from %s",
                     service->name,
                     session->ses_id,
                     session->client_dcb->user,
                     session->client_dcb->remote);
        }
    }
    else
    {
        MXS_INFO("Start %s client session [%lu] 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);
    }
    spinlock_acquire(&session_spin);
    /** Assign a session id and increase, insert session into list */
    session->ses_id = ++session_id;
    session->next = allSessions;
    allSessions = session;
    spinlock_release(&session_spin);
    atomic_add(&service->stats.n_sessions, 1);
    atomic_add(&service->stats.n_current, 1);
    CHK_SESSION(session);

    client_dcb->session = session;
    return SESSION_STATE_TO_BE_FREED == session->state ? NULL : session;
}
예제 #4
0
파일: session.c 프로젝트: bigshuai/MaxScale
/**
 * Deallocate the specified session
 *
 * @param session       The session to deallocate
 */
bool
session_free(SESSION *session)
{
    if (session && SESSION_STATE_DUMMY == session->state)
    {
        return true;
    }
    CHK_SESSION(session);

    /*
     * Remove one reference. If there are no references left,
     * free session.
     */
    if (atomic_add(&session->refcount, -1) > 1)
    {
        /* Must be one or more references left */
        return false;
    }
    session->state = SESSION_STATE_TO_BE_FREED;

    /* First of all remove from the linked list */
    spinlock_acquire(&session_spin);
    if (allSessions == session)
    {
        allSessions = session->next;
    }
    else
    {
        SESSION *chksession;
        chksession = allSessions;
        while (chksession && chksession->next != session)
        {
            chksession = chksession->next;
        }
        if (chksession)
        {
            chksession->next = session->next;
        }
    }
    spinlock_release(&session_spin);
    atomic_add(&session->service->stats.n_current, -1);

    /***
     *
     */
    if (session->client_dcb)
    {
        if (!DCB_IS_CLONE(session->client_dcb))
        {
            mysql_auth_free_client_data(session->client_dcb);
        }
        dcb_free_all_memory(session->client_dcb);
    }
    /**
     * If session is not child of some other session, free router_session.
     * Otherwise let the parent free it.
     */
    if (!session->ses_is_child && session->router_session)
    {
        session->service->router->freeSession(session->service->router_instance,
                                              session->router_session);
    }
    if (session->n_filters)
    {
        int i;
        for (i = 0; i < session->n_filters; i++)
        {
            if (session->filters[i].filter)
            {
                session->filters[i].filter->obj->closeSession(session->filters[i].instance,
                                                              session->filters[i].session);
            }
        }
        for (i = 0; i < session->n_filters; i++)
        {
            if (session->filters[i].filter)
            {
                session->filters[i].filter->obj->freeSession(session->filters[i].instance,
                                                             session->filters[i].session);
            }
        }
        free(session->filters);
    }

    MXS_INFO("Stopped %s client session [%lu]",
             session->service->name,
             session->ses_id);

    /** Disable trace and decrease trace logger counter */
    session_disable_log_priority(session, LOG_INFO);

    /** If session doesn't have parent referencing to it, it can be freed */
    if (!session->ses_is_child)
    {
        session->state = SESSION_STATE_FREE;
        free(session);
    }
    return true;
}
예제 #5
0
/**
 * Allocate a new session for a new client of the specified service.
 *
 * Create the link to the router session by calling the newSession
 * entry point of the router using the router instance of the
 * service this session is part of.
 *
 * @param service	The service this connection was established by
 * @param client_dcb	The client side DCB
 * @return		The newly created session or NULL if an error occured
 */
SESSION *
session_alloc(SERVICE *service, DCB *client_dcb)
{
        SESSION 	*session;

        session = (SESSION *)calloc(1, sizeof(SESSION));
        ss_info_dassert(session != NULL,
                        "Allocating memory for session failed.");
        
        if (session == NULL) {
                int eno = errno;
                errno = 0;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed to allocate memory for "
                        "session object due error %d, %s.",
                        eno,
                        strerror(eno))));
		goto return_session;
        }
#if defined(SS_DEBUG)
        session->ses_chk_top = CHK_NUM_SESSION;
        session->ses_chk_tail = CHK_NUM_SESSION;
#endif
        spinlock_init(&session->ses_lock);
        /*<
         * Prevent backend threads from accessing before session is completely
         * initialized.
         */
        spinlock_acquire(&session->ses_lock);
        session->service = service;
	session->client = client_dcb;
	session->n_filters = 0;
	memset(&session->stats, 0, sizeof(SESSION_STATS));
	session->stats.connect = time(0);
	session->state = SESSION_STATE_ALLOC;
        /*<
	 * 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
         * 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
         * point.
         */
        session->data = client_dcb->data;
	client_dcb->session = session;
	session->refcount = 1;
        /*<
         * This indicates that session is ready to be shared with backend
         * DCBs. Note that this doesn't mean that router is initialized yet!
         */
        session->state = SESSION_STATE_READY;
        
        /*< Release session lock */
        spinlock_release(&session->ses_lock);

	/*
	 * 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 the listener session
	 *
	 * Router session creation may create other DCBs that link to the
	 * session, therefore it is important that the session lock is
         * relinquished beforethe router call.
	 */
	if (client_dcb->state != DCB_STATE_LISTENING && 
                client_dcb->dcb_role != DCB_ROLE_INTERNAL)
	{
		session->router_session =
                    service->router->newSession(service->router_instance,
                                                session);
	
                if (session->router_session == NULL) {
                        /**
                         * Inform other threads that session is closing.
                         */
                        session->state = SESSION_STATE_STOPPING;
                        /*<
                         * Decrease refcount, set dcb's session pointer NULL
                         * and set session pointer to NULL.
                         */
                        session_free(session);
                        client_dcb->session = NULL;
                        session = NULL;
                        LOGIF(LE, (skygw_log_write_flush(
                                LOGFILE_ERROR,
                                "Error : Failed to create %s session.",
                                service->name)));
                        
                        goto return_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.
		 *
		 * 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.
		 */
		session->head.instance = service->router_instance;
		session->head.session = session->router_session;

		session->head.routeQuery = (void *)(service->router->routeQuery);

		session->tail.instance = session;
		session->tail.session = session;
		session->tail.clientReply = session_reply;

		if (service->n_filters > 0)
		{
			if (!session_setup_filters(session))
			{
				/**
				 * Inform other threads that session is closing.
				 */
				session->state = SESSION_STATE_STOPPING;
				/*<
				 * Decrease refcount, set dcb's session pointer NULL
				 * and set session pointer to NULL.
				 */
				session_free(session);
				client_dcb->session = NULL;
				session = NULL;
				LOGIF(LE, (skygw_log_write_flush(
					LOGFILE_ERROR,
					"Error : Failed to create %s session.",
					service->name)));
				goto return_session;
			}
		}
        }

	spinlock_acquire(&session_spin);
        
        if (session->state != SESSION_STATE_READY)
        {
                session_free(session);
                client_dcb->session = NULL;
                session = NULL;
                LOGIF(LE, (skygw_log_write_flush(
                        LOGFILE_ERROR,
                        "Error : Failed to create %s session.",
                        service->name)));
                spinlock_release(&session_spin);
        }
        else
        {
                session->state = SESSION_STATE_ROUTER_READY;
                session->next = allSessions;
                allSessions = session;
                spinlock_release(&session_spin);
                atomic_add(&service->stats.n_sessions, 1);
                atomic_add(&service->stats.n_current, 1);
                CHK_SESSION(session);
        }        
return_session:
	return session;
}
예제 #6
0
/**
 * Deallocate the specified session
 *
 * @param session	The session to deallocate
 */
bool session_free(
        SESSION *session)
{
        bool    succp = false;
        SESSION *ptr;
        int     nlink;
	int	i;

        CHK_SESSION(session);

        /*<
         * Remove one reference. If there are no references left,
         * free session.
         */
        nlink = session_unlink_dcb(session, NULL);

        if (nlink != 0) {
                ss_dassert(nlink > 0);
                goto return_succp;
        }
        
	/* First of all remove from the linked list */
	spinlock_acquire(&session_spin);
	if (allSessions == session)
	{
		allSessions = session->next;
	}
	else
	{
		ptr = allSessions;
		while (ptr && ptr->next != session)
		{
			ptr = ptr->next;
		}
		if (ptr)
			ptr->next = session->next;
	}
	spinlock_release(&session_spin);
	atomic_add(&session->service->stats.n_current, -1);

	/* Free router_session and session */
        if (session->router_session) {
                session->service->router->freeSession(
                        session->service->router_instance,
                        session->router_session);
        }
	if (session->n_filters)
	{
		for (i = 0; i < session->n_filters; i++)
		{
			session->filters[i].filter->obj->closeSession(
					session->filters[i].instance,
					session->filters[i].session);
		}
		for (i = 0; i < session->n_filters; i++)
		{
			session->filters[i].filter->obj->freeSession(
					session->filters[i].instance,
					session->filters[i].session);
		}
		free(session->filters);
	}
	free(session);
        succp = true;
        
return_succp :
        return succp;
}