Пример #1
0
/**
 * Close a session with the router, this is the mechanism
 * by which a router may cleanup data structure etc.
 *
 * @param instance		The router instance data
 * @param router_session	The session being closed
 */
static	void 	
closeSession(ROUTER *instance, void *router_session)
{
ROUTER_CLIENT_SES *router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
DCB*              backend_dcb;

        CHK_CLIENT_RSES(router_cli_ses);
        /**
         * Lock router client session for secure read and update.
         */
        if (rses_begin_locked_router_action(router_cli_ses))
        {
		/* decrease server current connection counter */
		atomic_add(&router_cli_ses->backend->server->stats.n_current, -1);

                backend_dcb = router_cli_ses->backend_dcb;
                router_cli_ses->backend_dcb = NULL;
                router_cli_ses->rses_closed = true;
                /** Unlock */
                rses_end_locked_router_action(router_cli_ses);
                
                /**
                 * Close the backend server connection
                 */
                if (backend_dcb != NULL) {
                        CHK_DCB(backend_dcb);
                        dcb_close(backend_dcb);
                }
        }
}
Пример #2
0
/** 
 * @node Acquires lock to router client session if it is not closed.
 *
 * Parameters:
 * @param rses - in, use
 *          
 *
 * @return true if router session was not closed. If return value is true
 * it means that router is locked, and must be unlocked later. False, if
 * router was closed before lock was acquired.
 *
 * 
 * @details (write detailed description here)
 *
 */
static bool rses_begin_locked_router_action(
        ROUTER_CLIENT_SES* rses)
{
        bool succp = false;
        
        CHK_CLIENT_RSES(rses);

        if (rses->rses_closed) {
                goto return_succp;
        }       
        spinlock_acquire(&rses->rses_lock);
        if (rses->rses_closed) {
                spinlock_release(&rses->rses_lock);
                goto return_succp;
        }
        succp = true;
        
return_succp:
        return succp;
}
Пример #3
0
/** 
 * @node Releases router client session lock.
 *
 * Parameters:
 * @param rses - <usage>
 *          <description>
 *
 * @return void
 *
 * 
 * @details (write detailed description here)
 *
 */
static void rses_end_locked_router_action(
        ROUTER_CLIENT_SES* rses)
{
        CHK_CLIENT_RSES(rses);
        spinlock_release(&rses->rses_lock);
}
Пример #4
0
/**
 * Associate a new session with this instance of the router.
 *
 * @param instance	The router instance data
 * @param session	The session itself
 * @return Session specific data for this session
 */
static	void	*
newSession(ROUTER *instance, SESSION *session)
{
ROUTER_INSTANCE	        *inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES       *client_rses;
BACKEND                 *candidate = NULL;
int                     i;
BACKEND *master_host = NULL;

        LOGIF(LD, (skygw_log_write_flush(
                LOGFILE_DEBUG,
                "%lu [newSession] new router session with session "
                "%p, and inst %p.",
                pthread_self(),
                session,
                inst)));


	client_rses = (ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES));

        if (client_rses == NULL) {
                return NULL;
	}

#if defined(SS_DEBUG)
        client_rses->rses_chk_top = CHK_NUM_ROUTER_SES;
        client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES;
#endif

	/**
         * Find the Master host from available servers
	 */
        master_host = get_root_master(inst->servers);

	/**
	 * Find a backend server to connect to. This is the extent of the
	 * load balancing algorithm we need to implement for this simple
	 * connection router.
	 */

	/*
	 * Loop over all the servers and find any that have fewer connections
         * than the candidate server.
	 *
	 * If a server has less connections than the current candidate we mark this
	 * as the new candidate to connect to.
	 *
	 * If a server has the same number of connections currently as the candidate
	 * and has had less connections over time than the candidate it will also
	 * become the new candidate. This has the effect of spreading the
         * connections over different servers during periods of very low load.
	 */
	for (i = 0; inst->servers[i]; i++) {
		if(inst->servers[i]) {
			LOGIF(LD, (skygw_log_write(
				LOGFILE_DEBUG,
				"%lu [newSession] Examine server in port %d with "
                                "%d connections. Status is %s, "
				"inst->bitvalue is %d",
                                pthread_self(),
				inst->servers[i]->server->port,
				inst->servers[i]->current_connection_count,
				STRSRVSTATUS(inst->servers[i]->server),
				inst->bitmask)));
		}

		if (SERVER_IN_MAINT(inst->servers[i]->server))
			continue;

		if (inst->servers[i]->weight == 0)
			continue;

		/* Check server status bits against bitvalue from router_options */
		if (inst->servers[i] &&
			SERVER_IS_RUNNING(inst->servers[i]->server) &&
			(inst->servers[i]->server->status & inst->bitmask & inst->bitvalue))
                {
			if (master_host) {
				if (inst->servers[i] == master_host && (inst->bitvalue & SERVER_SLAVE)) {
					/* skip root Master here, as it could also be slave of an external server
					 * that is not in the configuration.
					 * Intermediate masters (Relay Servers) are also slave and will be selected
					 * as Slave(s)
			 		 */

					continue;
				}
				if (inst->servers[i] == master_host && (inst->bitvalue & SERVER_MASTER)) {
					/* If option is "master" return only the root Master as there
					 * could be intermediate masters (Relay Servers)
					 * and they must not be selected.
			 	 	 */

					candidate = master_host;
					break;
				}
			} else {
					/* master_host is NULL, no master server.
					 * If requested router_option is 'master'
					 * candidate wll be NULL.
					 */
					if (inst->bitvalue & SERVER_MASTER) {
                                                candidate = NULL;
                                                break;
					}
			}

			/* If no candidate set, set first running server as
			our initial candidate server */
			if (candidate == NULL)
                        {
				candidate = inst->servers[i];
			}
                        else if ((inst->servers[i]->current_connection_count 
					* 1000) / inst->servers[i]->weight <
                                   (candidate->current_connection_count *
					1000) / candidate->weight)
                        {
				/* This running server has fewer
				connections, set it as a new candidate */
				candidate = inst->servers[i];
			}
                        else if ((inst->servers[i]->current_connection_count 
					* 1000) / inst->servers[i]->weight ==
                                   (candidate->current_connection_count *
					1000) / candidate->weight &&
                                 inst->servers[i]->server->stats.n_connections <
                                 candidate->server->stats.n_connections)
                        {
				/* This running server has the same number
				of connections currently as the candidate
				but has had fewer connections over time
				than candidate, set this server to candidate*/
				candidate = inst->servers[i];
			}
		}
	}

	/* There is no candidate server here!
	 * With router_option=slave a master_host could be set, so route traffic there.
	 * Otherwise, just clean up and return NULL
	 */
	if (!candidate) {
		if (master_host) {
			candidate = master_host;
		} else {
                	LOGIF(LE, (skygw_log_write_flush(
                      	  LOGFILE_ERROR,
                      	  "Error : Failed to create new routing session. "
                      	  "Couldn't find eligible candidate server. Freeing "
                       	 "allocated resources.")));
			free(client_rses);
			return NULL;
		}
	}

	client_rses->rses_capabilities = RCAP_TYPE_PACKET_INPUT;
        
	/*
	 * We now have the server with the least connections.
	 * Bump the connection count for this server
	 */
	atomic_add(&candidate->current_connection_count, 1);
	client_rses->backend = candidate;
        LOGIF(LD, (skygw_log_write(
                LOGFILE_DEBUG,
                "%lu [newSession] Selected server in port %d. "
                "Connections : %d\n",
                pthread_self(),
                candidate->server->port,
                candidate->current_connection_count)));

        /*
	 * Open a backend connection, putting the DCB for this
	 * connection in the client_rses->backend_dcb
	 */
        client_rses->backend_dcb = dcb_connect(candidate->server,
                                      session,
                                      candidate->server->protocol);
        if (client_rses->backend_dcb == NULL)
	{
                atomic_add(&candidate->current_connection_count, -1);
		free(client_rses);
		return NULL;
	}
        dcb_add_callback(
                         client_rses->backend_dcb,
                         DCB_REASON_NOT_RESPONDING,
                         &handle_state_switch,
                         client_rses);
        inst->stats.n_sessions++;

	/**
         * Add this session to the list of active sessions.
         */
	spinlock_acquire(&inst->lock);
	client_rses->next = inst->connections;
	inst->connections = client_rses;
	spinlock_release(&inst->lock);

        CHK_CLIENT_RSES(client_rses);

	skygw_log_write(
                LOGFILE_TRACE,
		 "Readconnroute: New session for server %s. "
                "Connections : %d",
		 candidate->server->unique_name,
		 candidate->current_connection_count);
	return (void *)client_rses;
}
Пример #5
0
/**
 * Associate a new session with this instance of the router.
 *
 * @param instance	The router instance data
 * @param session	The session itself
 * @return Session specific data for this session
 */
static	void	*
newSession(ROUTER *instance, SESSION *session)
{
    ROUTER_INSTANCE	        *inst = (ROUTER_INSTANCE *)instance;
    ROUTER_CLIENT_SES       *client_rses;
    BACKEND                 *candidate = NULL;
    int                     i;
    int			master_host = -1;

    LOGIF(LD, (skygw_log_write_flush(
                   LOGFILE_DEBUG,
                   "%lu [newSession] new router session with session "
                   "%p, and inst %p.",
                   pthread_self(),
                   session,
                   inst)));


    client_rses = (ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES));

    if (client_rses == NULL) {
        return NULL;
    }

#if defined(SS_DEBUG)
    client_rses->rses_chk_top = CHK_NUM_ROUTER_SES;
    client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES;
#endif

    /**
     * Find a backend server to connect to. This is the extent of the
     * load balancing algorithm we need to implement for this simple
     * connection router.
     */

    /*
     * Loop over all the servers and find any that have fewer connections
         * than the candidate server.
     *
     * If a server has less connections than the current candidate we mark this
     * as the new candidate to connect to.
     *
     * If a server has the same number of connections currently as the candidate
     * and has had less connections over time than the candidate it will also
     * become the new candidate. This has the effect of spreading the
         * connections over different servers during periods of very low load.
     */
    for (i = 0; inst->servers[i]; i++) {
        if(inst->servers[i]) {
            LOGIF(LD, (skygw_log_write(
                           LOGFILE_DEBUG,
                           "%lu [newSession] Examine server in port %d with "
                           "%d connections. Status is %d, "
                           "inst->bitvalue is %d",
                           pthread_self(),
                           inst->servers[i]->server->port,
                           inst->servers[i]->current_connection_count,
                           inst->servers[i]->server->status,
                           inst->bitmask)));
        }

        /*
         * If router_options=slave, get the running master
         * It will be used if there are no running slaves at all
         */
        if (inst->bitvalue == SERVER_SLAVE) {
            if (master_host < 0 && (SERVER_IS_MASTER(inst->servers[i]->server))) {
                master_host = i;
            }
        }

        if (inst->servers[i] &&
                SERVER_IS_RUNNING(inst->servers[i]->server) &&
                (inst->servers[i]->server->status & inst->bitmask) ==
                inst->bitvalue)
        {
            /* If no candidate set, set first running server as
            our initial candidate server */
            if (candidate == NULL)
            {
                candidate = inst->servers[i];
            }
            else if (inst->servers[i]->current_connection_count <
                     candidate->current_connection_count)
            {
                /* This running server has fewer
                connections, set it as a new candidate */
                candidate = inst->servers[i];
            }
            else if (inst->servers[i]->current_connection_count ==
                     candidate->current_connection_count &&
                     inst->servers[i]->server->stats.n_connections <
                     candidate->server->stats.n_connections)
            {
                /* This running server has the same number
                of connections currently as the candidate
                but has had fewer connections over time
                than candidate, set this server to candidate*/
                candidate = inst->servers[i];
            }
        }
    }

    /* There is no candidate server here!
     * With router_option=slave a master_host could be set, so route traffic there.
     * Otherwise, just clean up and return NULL
     */
    if (!candidate) {
        if (master_host >= 0) {
            candidate = inst->servers[master_host];
        } else {
            LOGIF(LE, (skygw_log_write_flush(
                           LOGFILE_ERROR,
                           "Error : Failed to create new routing session. "
                           "Couldn't find eligible candidate server. Freeing "
                           "allocated resources.")));
            free(client_rses);
            return NULL;
        }
    }

    client_rses->rses_capabilities = RCAP_TYPE_PACKET_INPUT;

    /*
     * We now have the server with the least connections.
     * Bump the connection count for this server
     */
    atomic_add(&candidate->current_connection_count, 1);
    client_rses->backend = candidate;
    LOGIF(LD, (skygw_log_write(
                   LOGFILE_DEBUG,
                   "%lu [newSession] Selected server in port %d. "
                   "Connections : %d\n",
                   pthread_self(),
                   candidate->server->port,
                   candidate->current_connection_count)));
    /*
    * Open a backend connection, putting the DCB for this
     * connection in the client_rses->backend_dcb
     */
    client_rses->backend_dcb = dcb_connect(candidate->server,
                                           session,
                                           candidate->server->protocol);
    if (client_rses->backend_dcb == NULL)
    {
        atomic_add(&candidate->current_connection_count, -1);
        free(client_rses);
        return NULL;
    }
    inst->stats.n_sessions++;

    /**
         * Add this session to the list of active sessions.
         */
    spinlock_acquire(&inst->lock);
    client_rses->next = inst->connections;
    inst->connections = client_rses;
    spinlock_release(&inst->lock);

    CHK_CLIENT_RSES(client_rses);

    return (void *)client_rses;
}