From 45aa40c10a28fb6bdd1a68ff08a0629f2f1af715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Sat, 27 Jul 2019 11:42:05 +0300 Subject: [PATCH] Fix RWBackend state tracking with multi-result queries If a query returned multiple resultsets and the connection was broken between the resultsets, the backend would not know that parts of the response were already sent. This is caused by the cyclic nature of the state machine when multi-result responses are being processed. To fix the problem, the result size is tracked to know how many bytes have been sent to the client. This is a backport of the MySQLProtocol::Result::size from 2.5(develop). --- include/maxscale/protocol/rwbackend.hh | 3 ++- server/modules/protocol/MySQL/rwbackend.cc | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/maxscale/protocol/rwbackend.hh b/include/maxscale/protocol/rwbackend.hh index 3a9f466b7..e046b7904 100644 --- a/include/maxscale/protocol/rwbackend.hh +++ b/include/maxscale/protocol/rwbackend.hh @@ -240,7 +240,7 @@ public: */ bool reply_has_started() const { - return m_reply_state != REPLY_STATE_START && m_reply_state != REPLY_STATE_DONE; + return m_size > 0 && m_reply_state != REPLY_STATE_DONE; } void process_packets(GWBUF* buffer); @@ -269,6 +269,7 @@ private: bool m_large_query = false; bool m_skip_next = false; Error m_error; + uint64_t m_size = 0;/**< Size of the response */ /** * @param it Iterator pointing to the command byte of an error packet. diff --git a/server/modules/protocol/MySQL/rwbackend.cc b/server/modules/protocol/MySQL/rwbackend.cc index 94337f2b1..c951fc5f4 100644 --- a/server/modules/protocol/MySQL/rwbackend.cc +++ b/server/modules/protocol/MySQL/rwbackend.cc @@ -45,6 +45,7 @@ bool RWBackend::execute_session_command() if (rval && expect_response) { set_reply_state(REPLY_STATE_START); + m_size = 0; } return rval; @@ -88,6 +89,7 @@ bool RWBackend::write(GWBUF* buffer, response_type type) { /** The server will reply to this command */ set_reply_state(REPLY_STATE_START); + m_size = 0; } uint8_t cmd = mxs_mysql_get_command(buffer); @@ -320,6 +322,8 @@ void RWBackend::process_packets(GWBUF* result) end.advance(len); uint8_t cmd = *it; + m_size += len; + // Ignore the tail end of a large packet large packet. Only resultsets can generate packets this large // and we don't care what the contents are and thus it is safe to ignore it. bool skip_next = m_skip_next;