Erase trailing unexpected ERR packets

If a resultset is followed by an ERR packet that is not expected
(e.g. server is shutting down), the packet must not be sent to the
client. This allows readwritesplit to replace the failing connection with
a new one thus hiding server shutdowns from clients.
This commit is contained in:
Markus Mäkelä
2019-06-14 11:55:30 +03:00
parent fc997b9e38
commit f8729c272e

View File

@ -535,12 +535,40 @@ void RWSplitSession::manage_transactions(RWBackend* backend, GWBUF* writebuf)
}
}
static bool server_is_shutting_down(GWBUF* writebuf)
namespace
{
bool server_is_shutting_down(GWBUF* writebuf)
{
uint64_t err = mxs_mysql_get_mysql_errno(writebuf);
return err == ER_SERVER_SHUTDOWN || err == ER_NORMAL_SHUTDOWN || err == ER_SHUTDOWN_COMPLETE;
}
mxs::Buffer::iterator skip_packet(mxs::Buffer::iterator it)
{
uint32_t len = *it++;
len |= (*it++) << 8;
len |= (*it++) << 16;
it.advance(len + 1); // Payload length plus the fourth header byte (packet sequence)
return it;
}
GWBUF* erase_last_packet(GWBUF* input)
{
mxs::Buffer buf(input);
auto it = buf.begin();
auto end = it;
while ((end = skip_packet(it)) != buf.end())
{
it = end;
}
buf.erase(it, end);
return buf.release();
}
}
void RWSplitSession::close_stale_connections()
{
auto current_rank = get_current_rank();
@ -606,10 +634,9 @@ void RWSplitSession::clientReply(GWBUF* writebuf, DCB* backend_dcb)
// The server sent an error that we didn't expect: treat it as if the connection was closed. The
// client shouldn't see this error as we can replace the closed connection.
// TODO: Erase trailing packets
if (mxs_mysql_is_err_packet(writebuf))
if (!(writebuf = erase_last_packet(writebuf)))
{
gwbuf_free(writebuf);
// Nothing to route to the client
return;
}
}