MXS-2603: Treat WSREP errors as ignorable errors
When a query returns a WSREP error, most of the time it is not something the client application is expecting. To prevent this from affecting the client, it can be treated the same way a transaction rollback is treated: ignore the error and try again.
This commit is contained in:
parent
45aa40c10a
commit
9d0c6b908a
@ -88,6 +88,13 @@ public:
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool is_wsrep_error() const
|
||||
{
|
||||
return m_code == 1047
|
||||
&& m_sql_state == "08S01"
|
||||
&& m_message == "WSREP has not yet prepared node for application use";
|
||||
}
|
||||
|
||||
bool is_unexpected_error() const
|
||||
{
|
||||
switch (m_code)
|
||||
|
@ -600,6 +600,48 @@ void RWSplitSession::close_stale_connections()
|
||||
}
|
||||
}
|
||||
|
||||
bool RWSplitSession::handle_ignorable_error(RWBackend* backend)
|
||||
{
|
||||
mxb_assert(session_trx_is_active(m_pSession) || can_retry_query());
|
||||
mxb_assert(m_expected_responses > 0);
|
||||
|
||||
bool ok = false;
|
||||
m_expected_responses--;
|
||||
|
||||
MXS_INFO("%s: %s", backend->error().is_rollback() ?
|
||||
"Server triggered transaction rollback, replaying transaction" :
|
||||
"WSREP not ready, retrying query", backend->error().message().c_str());
|
||||
|
||||
if (session_trx_is_active(m_pSession))
|
||||
{
|
||||
ok = start_trx_replay();
|
||||
}
|
||||
else
|
||||
{
|
||||
mxb_assert(backend->error().is_wsrep_error());
|
||||
|
||||
if (backend == m_current_master)
|
||||
{
|
||||
if (can_retry_query())
|
||||
{
|
||||
ok = retry_master_query(backend);
|
||||
}
|
||||
}
|
||||
else if (m_config.retry_failed_reads)
|
||||
{
|
||||
ok = true;
|
||||
retry_query(m_current_query.release());
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
session_reset_server_bookkeeping(m_pSession);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void RWSplitSession::clientReply(GWBUF* writebuf, DCB* backend_dcb)
|
||||
{
|
||||
DCB* client_dcb = backend_dcb->session->client_dcb;
|
||||
@ -638,16 +680,10 @@ void RWSplitSession::clientReply(GWBUF* writebuf, DCB* backend_dcb)
|
||||
}
|
||||
}
|
||||
|
||||
if (error && m_config.transaction_replay && error.is_rollback())
|
||||
if ((error.is_rollback() || error.is_wsrep_error()) && handle_ignorable_error(backend))
|
||||
{
|
||||
MXS_INFO("A retryable error: %s", error.message().c_str());
|
||||
|
||||
// writebuf was an error that can be handled by replaying the transaction.
|
||||
m_expected_responses--;
|
||||
|
||||
start_trx_replay();
|
||||
// We can ignore this error and treat it as if the connection to the server was broken.
|
||||
gwbuf_free(writebuf);
|
||||
session_reset_server_bookkeeping(m_pSession);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,7 @@ private:
|
||||
bool lock_to_master();
|
||||
bool is_locked_to_master() const;
|
||||
bool supports_hint(HINT_TYPE hint_type) const;
|
||||
bool handle_ignorable_error(mxs::RWBackend* backend);
|
||||
|
||||
inline bool can_retry_query() const
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user