diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 709ac254c..9bf706958 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -298,6 +298,26 @@ bool RWSplitSession::route_single_stmt(GWBUF *querybuf) else if (TARGET_IS_MASTER(route_target)) { succp = handle_master_is_target(&target); + + if (!succp && should_migrate_trx(target)) + { + MXS_INFO("Starting transaction migration from '%s' to '%s'", + m_current_master->name(), target->name()); + + /** + * Stash the current query so that the transaction replay treats + * it as if the query was interrupted. + */ + m_current_query.copy_from(querybuf); + + /** + * After the transaction replay has been started, the rest of + * the query processing needs to be skipped. This is done to avoid + * the error logging done when no valid target is found for a query + * as well as to prevent retrying of queries in the wrong order. + */ + return start_trx_replay(); + } } if (succp && target) @@ -895,6 +915,19 @@ void RWSplitSession::replace_master(SRWBackend& target) m_qc.master_replaced(); } +bool RWSplitSession::should_migrate_trx(SRWBackend& target) +{ + return m_config->transaction_replay && + // We have a target server and it's not the current master + target && target != m_current_master && + // Transaction replay is not active (replay is only attempted once) + !m_is_replay_active && + // We have an open transaction + session_trx_is_active(m_client->session) && + // The transaction can be replayed + m_can_replay_trx; +} + /** * @brief Handle master is the target * diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index 9ba318f49..521774c51 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -601,6 +601,7 @@ void RWSplitSession::clientReply(GWBUF *writebuf, DCB *backend_dcb) } else if (m_config->transaction_replay && session_trx_is_ending(m_client->session)) { + MXS_INFO("Transaction complete"); m_trx.close(); m_can_replay_trx = true; } diff --git a/server/modules/routing/readwritesplit/rwsplitsession.hh b/server/modules/routing/readwritesplit/rwsplitsession.hh index 9ea1f8ff9..bbc1b2d82 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.hh +++ b/server/modules/routing/readwritesplit/rwsplitsession.hh @@ -188,6 +188,7 @@ private: bool should_replace_master(mxs::SRWBackend& target); void replace_master(mxs::SRWBackend& target); + bool should_migrate_trx(mxs::SRWBackend& target); void log_master_routing_failure(bool found, mxs::SRWBackend& old_master, mxs::SRWBackend& curr_master); diff --git a/server/modules/routing/readwritesplit/trx.hh b/server/modules/routing/readwritesplit/trx.hh index 8803f6121..8cea12100 100644 --- a/server/modules/routing/readwritesplit/trx.hh +++ b/server/modules/routing/readwritesplit/trx.hh @@ -131,7 +131,6 @@ public: */ void close() { - MXS_INFO("Transaction is complete"); m_checksum.reset(); m_log.clear(); m_size = 0;