예제 #1
0
/**
 * Set a status bit in the server
 *
 * @param server	The server to update
 * @param bit		The bit to set for the server
 */
void
server_set_status(SERVER *server, int bit)
{
	server->status |= bit;
	
	/** clear error logged flag before the next failure */
	if (SERVER_IS_MASTER(server)) 
	{
		server->master_err_is_logged = false;
	}
}
예제 #2
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;
}