MXS-1549: Implement optimistic transaction execution

When the `optimistic_trx` mode is enabled, all transactions are started on
a slave server. If the client executes a query inside the transaction that
is not of a read-only nature, the transaction is rolled back and replayed
on the master.
This commit is contained in:
Markus Mäkelä
2018-06-24 19:46:26 +03:00
parent 391618d53b
commit 12398bfc26
4 changed files with 140 additions and 3 deletions

View File

@ -478,8 +478,20 @@ void RWSplitSession::clientReply(GWBUF *writebuf, DCB *backend_dcb)
return; // Nothing to route, return
}
if (m_config.transaction_replay && m_can_replay_trx &&
session_trx_is_active(m_client->session))
if (m_otrx_state == OTRX_ROLLBACK)
{
/** This is the response to the ROLLBACK. If it fails, we must close
* the connection. The replaying of the transaction can continue
* regardless of the ROLLBACK result. */
ss_dassert(backend == m_prev_target);
if (!mxs_mysql_is_ok_packet(writebuf))
{
poll_fake_hangup_event(backend_dcb);
}
}
else if (m_config.transaction_replay && m_can_replay_trx &&
session_trx_is_active(m_client->session))
{
if (!backend->has_session_commands())
{
@ -541,6 +553,15 @@ void RWSplitSession::clientReply(GWBUF *writebuf, DCB *backend_dcb)
// Server requested a local file, go into data streaming mode
m_qc.set_load_data_state(QueryClassifier::LOAD_DATA_ACTIVE);
}
if (m_otrx_state == OTRX_ROLLBACK)
{
// Transaction rolled back, start replaying it on the master
m_otrx_state = OTRX_INACTIVE;
start_trx_replay();
gwbuf_free(writebuf);
return;
}
}
else
{
@ -787,6 +808,20 @@ void RWSplitSession::handleError(GWBUF *errmsgbuf, DCB *problem_dcb,
can_continue = start_trx_replay();
backend->close();
}
else if (m_otrx_state != OTRX_INACTIVE)
{
/**
* The connection was closed mid-transaction or while we were
* executing the ROLLBACK. In both cases the transaction will
* be closed. We can safely start retrying the transaction
* on the master.
*/
ss_dassert(session_trx_is_active(session));
m_otrx_state = OTRX_INACTIVE;
can_continue = start_trx_replay();
backend->close();
}
else
{
/** Try to replace the failed connection with a new one */