Clean up unexpected error handling in readwritesplit
By using the Error class, the code can be cleaned up and simplified.
This commit is contained in:
@ -19,6 +19,7 @@
|
|||||||
#include <maxscale/backend.hh>
|
#include <maxscale/backend.hh>
|
||||||
#include <maxscale/modutil.hh>
|
#include <maxscale/modutil.hh>
|
||||||
#include <maxscale/response_stat.hh>
|
#include <maxscale/response_stat.hh>
|
||||||
|
#include <maxscale/protocol/mysql.hh>
|
||||||
|
|
||||||
namespace maxscale
|
namespace maxscale
|
||||||
{
|
{
|
||||||
@ -87,6 +88,21 @@ public:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_unexpected_error() const
|
||||||
|
{
|
||||||
|
switch (m_code)
|
||||||
|
{
|
||||||
|
case ER_CONNECTION_KILLED:
|
||||||
|
case ER_SERVER_SHUTDOWN:
|
||||||
|
case ER_NORMAL_SHUTDOWN:
|
||||||
|
case ER_SHUTDOWN_COMPLETE:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t code() const
|
uint32_t code() const
|
||||||
{
|
{
|
||||||
return m_code;
|
return m_code;
|
||||||
@ -121,7 +137,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_code { 0 };
|
uint16_t m_code {0};
|
||||||
std::string m_sql_state;
|
std::string m_sql_state;
|
||||||
std::string m_message;
|
std::string m_message;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -410,7 +410,7 @@ void RWBackend::process_reply(GWBUF* buffer)
|
|||||||
process_packets(buffer);
|
process_packets(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_reply_state() == REPLY_STATE_DONE)
|
if (get_reply_state() == REPLY_STATE_DONE && is_waiting_result())
|
||||||
{
|
{
|
||||||
ack_write();
|
ack_write();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -580,29 +580,15 @@ void RWSplitSession::clientReply(GWBUF* writebuf, DCB* backend_dcb)
|
|||||||
DCB* client_dcb = backend_dcb->session->client_dcb;
|
DCB* client_dcb = backend_dcb->session->client_dcb;
|
||||||
RWBackend* backend = get_backend_from_dcb(backend_dcb);
|
RWBackend* backend = get_backend_from_dcb(backend_dcb);
|
||||||
|
|
||||||
if (backend->get_reply_state() == REPLY_STATE_DONE)
|
if (backend->get_reply_state() == REPLY_STATE_DONE
|
||||||
|
&& !connection_was_killed(writebuf)
|
||||||
|
&& !server_is_shutting_down(writebuf))
|
||||||
{
|
{
|
||||||
if (connection_was_killed(writebuf))
|
/** If we receive an unexpected response from the server, the internal
|
||||||
{
|
* logic cannot handle this situation. Routing the reply straight to
|
||||||
// The connection was killed, we can safely ignore it. When the TCP connection is
|
* the client should be the safest thing to do at this point. */
|
||||||
// closed, the router's error handling will sort it out.
|
log_unexpected_response(backend, writebuf, m_current_query.get());
|
||||||
gwbuf_free(writebuf);
|
MXS_SESSION_ROUTE_REPLY(backend_dcb->session, writebuf);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/** If we receive an unexpected response from the server, the internal
|
|
||||||
* logic cannot handle this situation. Routing the reply straight to
|
|
||||||
* the client should be the safest thing to do at this point. */
|
|
||||||
log_unexpected_response(backend, writebuf, m_current_query.get());
|
|
||||||
MXS_SESSION_ROUTE_REPLY(backend_dcb->session, writebuf);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (backend->get_reply_state() == REPLY_STATE_START && server_is_shutting_down(writebuf))
|
|
||||||
{
|
|
||||||
// The server is shutting down, ignore this error and wait for the TCP connection to die.
|
|
||||||
// This allows the query to be retried on another server without the client noticing it.
|
|
||||||
gwbuf_free(writebuf);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +601,19 @@ void RWSplitSession::clientReply(GWBUF* writebuf, DCB* backend_dcb)
|
|||||||
|
|
||||||
const RWBackend::Error& error = backend->error();
|
const RWBackend::Error& error = backend->error();
|
||||||
|
|
||||||
|
if (error.is_unexpected_error())
|
||||||
|
{
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
gwbuf_free(writebuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error && m_config.transaction_replay && error.is_rollback())
|
if (error && m_config.transaction_replay && error.is_rollback())
|
||||||
{
|
{
|
||||||
MXS_INFO("A retryable error: %s", error.message().c_str());
|
MXS_INFO("A retryable error: %s", error.message().c_str());
|
||||||
|
|||||||
Reference in New Issue
Block a user