MXS-1503: Remove redundant code

Moved session command execution into the Backend class itself as the
session commands are defined as a related part of it. This allows all
connections to execute session commands if some are available.

Removed explicit SERVER_REF usage in the readwritesplit connection
creation code and replaced it with SRWBackend. This allows the removal of
the get_root_master_backend function which duplicated the functionality in
get_root_master.
This commit is contained in:
Markus Mäkelä
2018-03-27 21:39:59 +03:00
parent a1b5fcd4ff
commit be2186c8f1
6 changed files with 64 additions and 165 deletions

View File

@ -143,10 +143,11 @@ public:
* @brief Create a new connection * @brief Create a new connection
* *
* @param session The session to which the connection is linked * @param session The session to which the connection is linked
* @param sescmd Pointer to a list of session commands to execute
* *
* @return True if connection was successfully created * @return True if connection was successfully created
*/ */
bool connect(MXS_SESSION* session); bool connect(MXS_SESSION* session, SessionCommandList* sescmd = NULL);
/** /**
* @brief Close the backend * @brief Close the backend

View File

@ -176,7 +176,7 @@ void Backend::set_state(backend_state state)
m_state |= state; m_state |= state;
} }
bool Backend::connect(MXS_SESSION* session) bool Backend::connect(MXS_SESSION* session, SessionCommandList* sescmd)
{ {
bool rval = false; bool rval = false;
@ -186,6 +186,16 @@ bool Backend::connect(MXS_SESSION* session)
m_state = IN_USE; m_state = IN_USE;
atomic_add(&m_backend->connections, 1); atomic_add(&m_backend->connections, 1);
rval = true; rval = true;
if (sescmd && sescmd->size())
{
append_session_command(*sescmd);
if (!execute_session_command())
{
rval = false;
}
}
} }
else else
{ {

View File

@ -441,8 +441,7 @@ static bool handle_error_new_connection(RWSplit *inst,
} }
else else
{ {
succp = select_connect_backend_servers(myrses->rses_nbackends, max_nslaves, succp = select_connect_backend_servers(inst, ses, myrses->backends,
ses, inst->config(), myrses->backends,
myrses->current_master, &myrses->sescmd_list, myrses->current_master, &myrses->sescmd_list,
&myrses->expected_responses, &myrses->expected_responses,
connection_type::SLAVE); connection_type::SLAVE);
@ -770,8 +769,7 @@ RWSplitSession* RWSplitSession::create(RWSplit* router, MXS_SESSION* session)
SRWBackend master; SRWBackend master;
if (select_connect_backend_servers(router->service()->n_dbref, router->max_slave_count(), if (select_connect_backend_servers(router, session, backends, master,
session, router->config(), backends, master,
NULL, NULL, connection_type::ALL)) NULL, NULL, connection_type::ALL))
{ {
if ((rses = new RWSplitSession(router, session, backends, master))) if ((rses = new RWSplitSession(router, session, backends, master)))

View File

@ -93,15 +93,13 @@ enum connection_type
SLAVE SLAVE
}; };
bool select_connect_backend_servers(int router_nservers, bool select_connect_backend_servers(RWSplit *inst, MXS_SESSION *session,
int max_nslaves,
MXS_SESSION *session,
const Config& config,
SRWBackendList& backends, SRWBackendList& backends,
SRWBackend& current_master, SRWBackend& current_master,
mxs::SessionCommandList* sescmd, mxs::SessionCommandList* sescmd,
int* expected_responses, int* expected_responses,
connection_type type); connection_type type);
SRWBackend get_root_master(const SRWBackendList& backends);
/* /*
* The following are implemented in rwsplit_tmp_table_multi.c * The following are implemented in rwsplit_tmp_table_multi.c
*/ */

View File

@ -35,8 +35,6 @@
extern int (*criteria_cmpfun[LAST_CRITERIA])(const SRWBackend&, const SRWBackend&); extern int (*criteria_cmpfun[LAST_CRITERIA])(const SRWBackend&, const SRWBackend&);
static SRWBackend get_root_master_backend(RWSplitSession *rses);
/** /**
* Find out which of the two backend servers has smaller value for select * Find out which of the two backend servers has smaller value for select
* criteria property. * criteria property.
@ -345,9 +343,6 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype,
return rses->target_node; return rses->target_node;
} }
/** get root master from available servers */
SRWBackend master = get_root_master_backend(rses);
if (name) /*< Choose backend by name from a hint */ if (name) /*< Choose backend by name from a hint */
{ {
ss_dassert(btype != BE_MASTER); /*< Master dominates and no name should be passed with it */ ss_dassert(btype != BE_MASTER); /*< Master dominates and no name should be passed with it */
@ -462,26 +457,19 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype,
*/ */
else if (btype == BE_MASTER) else if (btype == BE_MASTER)
{ {
if (master) /** get root master from available servers */
{ SRWBackend master = get_root_master(rses->backends);
/** It is possible for the server status to change at any point in time
* so copying it locally will make possible error messages
* easier to understand */
SERVER server;
server.status = master->server()->status;
if (master->in_use()) if (master && master->in_use())
{ {
if (SERVER_IS_MASTER(&server)) if (master->is_master())
{ {
rval = master; rval = master;
} }
else else
{ {
MXS_ERROR("Server '%s' should be master but is %s instead " MXS_ERROR("Server '%s' does not have the master state and "
"and can't be chosen as the master.", "can't be chosen as the master.", master->name());
master->name(),
STRSRVSTATUS(&server));
} }
} }
else else
@ -490,7 +478,6 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype,
master->name()); master->name());
} }
} }
}
return rval; return rval;
} }
@ -943,52 +930,3 @@ bool handle_got_target(RWSplit *inst, RWSplitSession *rses,
return false; return false;
} }
} }
/**
* @brief Get the root master server from MySQL replication tree
*
* Finds the server with the lowest replication depth level which has the master
* status. Servers are checked even if they are in 'maintenance'.
*
* @param rses Router client session
*
* @return The backend that points to the master server or an empty reference
* if the master cannot be found
*/
static SRWBackend get_root_master_backend(RWSplitSession *rses)
{
SRWBackend candidate;
SERVER master = {};
for (SRWBackendList::iterator it = rses->backends.begin();
it != rses->backends.end(); it++)
{
SRWBackend& backend = *it;
if (backend->in_use())
{
if (backend == rses->current_master)
{
/** Store master state for better error reporting */
master.status = backend->server()->status;
}
if (backend->is_master())
{
if (!candidate ||
(backend->server()->depth < candidate->server()->depth))
{
candidate = backend;
}
}
}
}
if (!candidate && rses->rses_config.master_failure_mode == RW_FAIL_INSTANTLY &&
rses->current_master && rses->current_master->in_use())
{
MXS_ERROR("Could not find master among the backend servers. "
"Previous master's state : %s", STRSRVSTATUS(&master));
}
return candidate;
}

View File

@ -36,10 +36,10 @@
* *
* @return True if this server is a valid slave candidate * @return True if this server is a valid slave candidate
*/ */
static bool valid_for_slave(const SRWBackend& backend, const SERVER_REF *master) static bool valid_for_slave(const SRWBackend& backend, const SRWBackend& master)
{ {
return (backend->is_slave() || backend->is_relay()) && return (backend->is_slave() || backend->is_relay()) &&
(master == NULL || (backend->server() != master->server)); (!master || backend != master);
} }
/** /**
@ -54,7 +54,7 @@ static bool valid_for_slave(const SRWBackend& backend, const SERVER_REF *master)
* *
* @return The best slave backend reference or NULL if no candidates could be found * @return The best slave backend reference or NULL if no candidates could be found
*/ */
static SRWBackend get_slave_candidate(const SRWBackendList& backends, const SERVER_REF *master, static SRWBackend get_slave_candidate(const SRWBackendList& backends, const SRWBackend& master,
int (*cmpfun)(const SRWBackend&, const SRWBackend&)) int (*cmpfun)(const SRWBackend&, const SRWBackend&))
{ {
SRWBackend candidate; SRWBackend candidate;
@ -239,44 +239,25 @@ static void log_server_connections(select_criteria_t criteria, const SRWBackendL
} }
} }
} }
/**
* @brief Find the master server that is at the root of the replication tree
*
* @param rses Router client session
*
* @return The root master reference or NULL if no master is found
*/
static SERVER_REF* get_root_master(const SRWBackendList& backends)
{
SERVER_REF *master_host = NULL;
for (SRWBackendList::const_iterator it = backends.begin(); SRWBackend get_root_master(const SRWBackendList& backends)
it != backends.end(); it++)
{ {
SERVER_REF* b = (*it)->backend(); SRWBackend master;
if (SERVER_IS_MASTER(b->server)) for (auto it = backends.begin(); it != backends.end(); it++)
{ {
if (master_host == NULL || auto b = *it;
(b->server->depth < master_host->server->depth))
if (b->is_master() && (!master || b->server()->depth < master->server()->depth))
{ {
master_host = b; master = b;
}
} }
} }
return master_host; return master;
} }
/** std::pair<int, int> get_slave_counts(SRWBackendList& backends, SRWBackend& master)
* Get the total number of slaves and number of connected slaves
*
* @param backends List of backend servers
* @param master The master server or NULL for no master
*
* @return the total number of slaves and the connected slave count
*/
std::pair<int, int> get_slave_counts(SRWBackendList& backends, SERVER_REF* master)
{ {
int slaves_found = 0; int slaves_found = 0;
int slaves_connected = 0; int slaves_connected = 0;
@ -301,55 +282,35 @@ std::pair<int, int> get_slave_counts(SRWBackendList& backends, SERVER_REF* maste
} }
/** /**
* @brief Search suitable backend servers from those of router instance * Select and connect to backend servers
* *
* It is assumed that there is only one master among servers of a router instance. * @param inst Router instance
* As a result, the first master found is chosen. There will possibly be more
* backend references than connected backends because only those in correct state
* are connected to.
*
* @param router_nservers Number of backend servers
* @param max_nslaves Upper limit for the number of slaves
* @param select_criteria Slave selection criteria
* @param session Client session * @param session Client session
* @param router Router instance * @param backends List of backend servers
* @param rses Router client session * @param current_master The current master server
* @param sescmd_list List of session commands to execute
* @param expected_responses Pointer where number of expected responses are written
* @param type Connection type, ALL for all types, SLAVE for slaves only * @param type Connection type, ALL for all types, SLAVE for slaves only
* *
* @return True if at least one master and one slave was found * @return True if session can continue
*/ */
bool select_connect_backend_servers(int router_nservers, bool select_connect_backend_servers(RWSplit *inst, MXS_SESSION *session,
int max_nslaves,
MXS_SESSION *session,
const Config& config,
SRWBackendList& backends, SRWBackendList& backends,
SRWBackend& current_master, SRWBackend& current_master,
mxs::SessionCommandList* sescmd_list, mxs::SessionCommandList* sescmd_list,
int* expected_responses, int* expected_responses,
connection_type type) connection_type type)
{ {
SERVER_REF *master = get_root_master(backends); SRWBackend master = get_root_master(backends);
if (!master && config.master_failure_mode == RW_FAIL_INSTANTLY) if (!master && inst->config().master_failure_mode == RW_FAIL_INSTANTLY)
{ {
MXS_ERROR("Couldn't find suitable Master from %d candidates.", router_nservers); MXS_ERROR("Couldn't find suitable Master from %lu candidates.", backends.size());
return false; return false;
} }
/**
* New session:
*
* Connect to both master and slaves
*
* Existing session:
*
* Master is already connected or we don't have a master. The function was
* called because new slaves must be selected to replace failed ones.
*/
bool master_connected = type == SLAVE || current_master;
/** Check slave selection criteria and set compare function */ /** Check slave selection criteria and set compare function */
select_criteria_t select_criteria = config.slave_selection_criteria; select_criteria_t select_criteria = inst->config().slave_selection_criteria;
int (*cmpfun)(const SRWBackend&, const SRWBackend&) = criteria_cmpfun[select_criteria]; int (*cmpfun)(const SRWBackend&, const SRWBackend&) = criteria_cmpfun[select_criteria];
ss_dassert(cmpfun); ss_dassert(cmpfun);
@ -358,14 +319,14 @@ bool select_connect_backend_servers(int router_nservers,
log_server_connections(select_criteria, backends); log_server_connections(select_criteria, backends);
} }
if (!master_connected) if (type == ALL)
{ {
/** Find a master server */ /** Find a master server */
for (SRWBackendList::const_iterator it = backends.begin(); it != backends.end(); it++) for (SRWBackendList::const_iterator it = backends.begin(); it != backends.end(); it++)
{ {
const SRWBackend& backend = *it; const SRWBackend& backend = *it;
if (backend->can_connect() && master && backend->server() == master->server) if (backend->can_connect() && master && backend == master)
{ {
if (backend->connect(session)) if (backend->connect(session))
{ {
@ -379,6 +340,7 @@ bool select_connect_backend_servers(int router_nservers,
auto counts = get_slave_counts(backends, master); auto counts = get_slave_counts(backends, master);
int slaves_found = counts.first; int slaves_found = counts.first;
int slaves_connected = counts.second; int slaves_connected = counts.second;
int max_nslaves = inst->max_slave_count();
ss_dassert(slaves_connected < max_nslaves || max_nslaves == 0); ss_dassert(slaves_connected < max_nslaves || max_nslaves == 0);
@ -387,27 +349,19 @@ bool select_connect_backend_servers(int router_nservers,
backend && slaves_connected < max_nslaves; backend && slaves_connected < max_nslaves;
backend = get_slave_candidate(backends, master, cmpfun)) backend = get_slave_candidate(backends, master, cmpfun))
{ {
if (backend->can_connect() && backend->connect(session)) if (backend->can_connect() && backend->connect(session, sescmd_list))
{ {
if (sescmd_list && sescmd_list->size()) if (sescmd_list && sescmd_list->size())
{
backend->append_session_command(*sescmd_list);
if (backend->execute_session_command())
{ {
if (expected_responses) if (expected_responses)
{ {
(*expected_responses)++; (*expected_responses)++;
} }
}
slaves_connected++; slaves_connected++;
} }
} }
else
{
slaves_connected++;
}
}
}
if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO)) if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
{ {