diff --git a/include/maxscale/session_command.hh b/include/maxscale/session_command.hh index d1782113a..75a846ded 100644 --- a/include/maxscale/session_command.hh +++ b/include/maxscale/session_command.hh @@ -89,6 +89,17 @@ public: */ bool eq(const SessionCommand& rhs) const; + /** + * Mark the session command as a re-execution of another command + * + * This function makes the current command's buffer a reference to the other + * command's buffer. The commands will still have separate positions and + * reply statuses. + * + * @param rhs Session command whose data is used + */ + void mark_as_duplicate(const SessionCommand& rhs); + private: mxs::Buffer m_buffer; /**< The buffer containing the command */ uint8_t m_command; /**< The command being executed */ diff --git a/server/core/session_command.cc b/server/core/session_command.cc index 241a75bc4..24d3b907a 100644 --- a/server/core/session_command.cc +++ b/server/core/session_command.cc @@ -92,4 +92,11 @@ std::string SessionCommand::to_string() return str; } +void SessionCommand::mark_as_duplicate(const SessionCommand& rhs) +{ + ss_dassert(eq(rhs)); + // The commands now share the mxs::Buffer that contains the actual command + m_buffer = rhs.m_buffer; +} + } diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 347046ab0..d91768ab7 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -368,52 +368,27 @@ bool RWSplitSession::route_single_stmt(GWBUF *querybuf) } /** - * Purge session command history + * Compress session command history + * + * This function removes data duplication by sharing buffers between session + * commands that have identical data. Only one copy of the actual data is stored + * for each unique session command. * * @param sescmd Executed session command */ -void RWSplitSession::purge_history(mxs::SSessionCommand& sescmd) +void RWSplitSession::compress_history(mxs::SSessionCommand& sescmd) { - /** - * We can try to purge duplicate text protocol session commands. This - * makes the history size smaller but at the cost of being able to handle - * the more complex user variable modifications. To keep the best of both - * worlds, keeping the first and last copy of each command should be - * an adequate compromise. This way executing the following SQL will still - * produce the correct result. - * - * USE test; - * SET @myvar = (SELECT COUNT(*) FROM t1); - * USE test; - * - * Another option would be to keep the first session command but that would - * require more work to be done in the session command response processing. - * This would be a better alternative but the gain might not be optimal. - */ - - // As the PS handles map to explicit IDs, we must retain all COM_STMT_PREPARE commands - if (sescmd->get_command() != MXS_COM_STMT_PREPARE) + auto eq = [&](mxs::SSessionCommand& scmd) { - auto eq = [&](mxs::SSessionCommand& scmd) - { - return scmd->eq(*sescmd); - }; + return scmd->eq(*sescmd); + }; - auto first = std::find_if(m_sescmd_list.begin(), m_sescmd_list.end(), eq); + auto first = std::find_if(m_sescmd_list.begin(), m_sescmd_list.end(), eq); - if (first != m_sescmd_list.end()) - { - // We have at least one of these commands. See if we have a second one - auto second = std::find_if(std::next(first), m_sescmd_list.end(), eq); - - if (second != m_sescmd_list.end()) - { - // We have a total of three commands, remove the middle one - auto old_cmd = *second; - m_sescmd_responses.erase(old_cmd->get_position()); - m_sescmd_list.erase(second); - } - } + if (first != m_sescmd_list.end()) + { + // Duplicate command, use a reference of the old command instead of duplicating it + sescmd->mark_as_duplicate(**first); } } @@ -541,7 +516,7 @@ bool RWSplitSession::route_session_write(GWBUF *querybuf, uint8_t command, uint3 } else { - purge_history(sescmd); + compress_history(sescmd); m_sescmd_list.push_back(sescmd); } diff --git a/server/modules/routing/readwritesplit/rwsplitsession.hh b/server/modules/routing/readwritesplit/rwsplitsession.hh index ac2e1bdb3..2826e8d79 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.hh +++ b/server/modules/routing/readwritesplit/rwsplitsession.hh @@ -164,7 +164,7 @@ private: const mxs::SRWBackendList& backends, const mxs::SRWBackend& master); void process_sescmd_response(mxs::SRWBackend& backend, GWBUF** ppPacket); - void purge_history(mxs::SSessionCommand& sescmd); + void compress_history(mxs::SSessionCommand& sescmd); bool route_session_write(GWBUF *querybuf, uint8_t command, uint32_t type); void continue_large_session_write(GWBUF *querybuf, uint32_t type);