MXS-1503: Restore slave reconnection

The slave connections can now be recovered after a failure as long as the
session command history is enabled. In comparison to the old
functionality, the server now replaces the connection when a query is
received instead of reconnecting when the slave fails.

As a negative side effect of this change, the max_slave_connections is no
longer enforced after the connection is created. To fix this broken
functionality, the connected slaves need to be preferred over unconnected
ones. This will be added in a follow-up commit.
This commit is contained in:
Markus Mäkelä
2018-03-28 12:38:54 +03:00
parent 3d63d18bdd
commit 4cf9bec10b

View File

@ -98,6 +98,38 @@ static inline bool locked_to_master(RWSplitSession *rses)
return rses->large_query || (rses->current_master && rses->target_node == rses->current_master);
}
static bool prepare_target(RWSplitSession* rses, SRWBackend& target, route_target_t route_target)
{
bool rval = true;
// Check if we need to connect to the server in order to use it
if (!target->in_use() && target->can_connect())
{
if (TARGET_IS_SLAVE(route_target) ||
(rses->rses_config.master_reconnection && TARGET_IS_MASTER(route_target)))
{
if ((!rses->rses_config.disable_sescmd_history || rses->recv_sescmd == 0))
{
rval = target->connect(rses->client_dcb->session, &rses->sescmd_list);
}
else
{
MXS_ERROR("Cannot reconnect to server '%s', session command"
" history is disabled (session has executed"
" %lu session commands).", target->name(), rses->recv_sescmd);
}
}
else if (TARGET_IS_MASTER(route_target))
{
MXS_ERROR("The connection to the master was lost and the connection "
"could be recreated but 'master_reconnection' is not enabled.");
rval = false;
}
}
return rval;
}
/**
* Routing function. Find out query type, backend type, and target DCB(s).
* Then route query to found target(s).
@ -167,30 +199,6 @@ bool route_single_stmt(RWSplit *inst, RWSplitSession *rses, GWBUF *querybuf, con
{
succp = handle_master_is_target(inst, rses, &target);
// Check if we need to connect to the master server in order to use it
if (succp && target && !target->in_use() && target->can_connect())
{
if (rses->rses_config.master_reconnection)
{
if ((!rses->rses_config.disable_sescmd_history || rses->recv_sescmd == 0))
{
target->connect(rses->client_dcb->session, &rses->sescmd_list);
}
else
{
MXS_ERROR("Cannot reconnect to master, session command"
" history is disabled (session has executed"
" %lu session commands).", rses->recv_sescmd);
}
}
else
{
MXS_ERROR("The connection to the master was lost but "
"'master_reconnection' is not enabled.");
succp = false;
}
}
if (!rses->rses_config.strict_multi_stmt &&
!rses->rses_config.strict_sp_calls &&
rses->target_node == rses->current_master)
@ -200,8 +208,9 @@ bool route_single_stmt(RWSplit *inst, RWSplitSession *rses, GWBUF *querybuf, con
}
}
if (target && succp) /*< Have DCB of the target backend */
if (succp && target && prepare_target(rses, target, route_target))
{
// Target server was found and is in the correct state
ss_dassert(!store_stmt || TARGET_IS_SLAVE(route_target));
succp = handle_got_target(inst, rses, querybuf, target, store_stmt);
@ -215,6 +224,10 @@ bool route_single_stmt(RWSplit *inst, RWSplitSession *rses, GWBUF *querybuf, con
MXS_INFO("COM_STMT_EXECUTE on %s", target->uri());
}
}
else
{
succp = false;
}
}
if (succp && inst->config().connection_keepalive &&
@ -381,8 +394,7 @@ SRWBackend get_slave_backend(RWSplitSession *rses, int max_rlag)
{
auto& backend = *it;
if (backend->in_use() && // Backend is in use
(backend->is_master() || backend->is_slave()) && // Either a master or a slave
if ((backend->is_master() || backend->is_slave()) && // Either a master or a slave
rpl_lag_is_ok(backend, max_rlag)) // Not lagging too much
{
if (!rval)
@ -858,7 +870,7 @@ bool handle_got_target(RWSplit *inst, RWSplitSession *rses,
mxs::Backend::response_type response = mxs::Backend::NO_RESPONSE;
rses->wait_gtid_state = EXPECTING_NOTHING;
uint8_t cmd = mxs_mysql_get_command(querybuf);
GWBUF *send_buf = gwbuf_clone(querybuf); ;
GWBUF *send_buf = gwbuf_clone(querybuf);
if (cmd == COM_QUERY && inst->config().enable_causal_read && rses->gtid_pos != "")
{
send_buf = add_prefix_wait_gtid(inst, rses, target->server(), send_buf);