Share data between identical session commands
If two or more session commands contain identical buffers, the buffer of the first session command is shared between the others. This reduces the amount of memory used to store repeated executions of session commands. The purging of session command history in readwritesplit was replaced with session command de-duplication. This was done to prevent problems that could arise when the order of session commands plays a significant role.
This commit is contained in:
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -368,31 +368,15 @@ 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)
|
||||
{
|
||||
/**
|
||||
* 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)
|
||||
void RWSplitSession::compress_history(mxs::SSessionCommand& sescmd)
|
||||
{
|
||||
auto eq = [&](mxs::SSessionCommand& scmd)
|
||||
{
|
||||
@ -403,17 +387,8 @@ void RWSplitSession::purge_history(mxs::SSessionCommand& sescmd)
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user