Return results as sets of packets

Returning the results of a query as a set of packets is currently more
efficient. This is mainly due to the fact that each individual packet for
single packet routing is allocated from the heap which causes a
significant loss in performance.

Took the new capability into use in readwritesplit and modified the
reply_is_complete function to work with non-contiguous results.
This commit is contained in:
Markus Mäkelä
2017-10-09 16:14:36 +03:00
parent 3015e6c97d
commit d64cd5cab8
4 changed files with 65 additions and 126 deletions

View File

@ -515,55 +515,6 @@ static bool route_stored_query(RWSplitSession *rses)
return rval;
}
static inline bool is_eof(GWBUF* buffer, size_t len)
{
uint8_t* data = GWBUF_DATA(buffer);
return data[MYSQL_HEADER_LEN] == MYSQL_REPLY_EOF &&
len == MYSQL_EOF_PACKET_LEN - MYSQL_HEADER_LEN;
}
static inline bool is_ok(GWBUF* buffer)
{
uint8_t* data = GWBUF_DATA(buffer);
return data[MYSQL_HEADER_LEN] == MYSQL_REPLY_OK;
}
static inline bool more_results_exist(GWBUF* buffer)
{
ss_dassert(is_eof(buffer, gw_mysql_get_byte3(GWBUF_DATA(buffer))) ||
mxs_mysql_is_ok_packet(buffer));
ss_dassert(GWBUF_IS_CONTIGUOUS(buffer));
uint8_t* ptr = GWBUF_DATA(buffer) + MYSQL_HEADER_LEN + 1;
ptr += mxs_leint_bytes(ptr);
ptr += mxs_leint_bytes(ptr);
uint16_t status = gw_mysql_get_byte2(ptr);
return status & SERVER_MORE_RESULTS_EXIST;
}
static inline bool is_result_set(GWBUF *buffer)
{
bool rval = false;
switch (GWBUF_DATA(buffer)[MYSQL_HEADER_LEN])
{
case MYSQL_REPLY_OK:
case MYSQL_REPLY_ERR:
case MYSQL_REPLY_LOCAL_INFILE:
case MYSQL_REPLY_EOF:
/** Not a result set */
break;
default:
rval = true;
break;
}
return rval;
}
/**
* @brief Check if we have received a complete reply from the backend
*
@ -575,11 +526,12 @@ static inline bool is_result_set(GWBUF *buffer)
bool reply_is_complete(SRWBackend& backend, GWBUF *buffer)
{
if (backend->get_reply_state() == REPLY_STATE_START &&
(!is_result_set(buffer) || GWBUF_IS_COLLECTED_RESULT(buffer)))
(!mxs_mysql_is_result_set(buffer) || GWBUF_IS_COLLECTED_RESULT(buffer)))
{
if (GWBUF_IS_COLLECTED_RESULT(buffer) ||
backend->current_command() == MXS_COM_STMT_PREPARE ||
!is_ok(buffer) || !more_results_exist(buffer))
!mxs_mysql_is_ok_packet(buffer) ||
!mxs_mysql_more_results_after_ok(buffer))
{
/** Not a result set, we have the complete response */
LOG_RS(backend, REPLY_STATE_DONE);
@ -588,21 +540,11 @@ bool reply_is_complete(SRWBackend& backend, GWBUF *buffer)
}
else
{
int n_eof = backend->get_reply_state() == REPLY_STATE_RSET_ROWS ? 1 : 0;
size_t len = gw_mysql_get_byte3(GWBUF_DATA(buffer));
if (len == GW_MYSQL_MAX_PACKET_LEN)
{
backend->set_large_packet(true);
}
else if (backend->is_large_packet())
{
backend->set_large_packet(false);
}
else if (is_eof(buffer, len))
{
n_eof++;
}
bool more = false;
modutil_state state = {backend->is_large_packet()};
int n_old_eof = backend->get_reply_state() == REPLY_STATE_RSET_ROWS ? 1 : 0;
int n_eof = modutil_count_signal_packets(buffer, n_old_eof, &more, &state);
backend->set_large_packet(state.state);
if (n_eof == 0)
{
@ -624,7 +566,7 @@ bool reply_is_complete(SRWBackend& backend, GWBUF *buffer)
LOG_RS(backend, REPLY_STATE_DONE);
backend->set_reply_state(REPLY_STATE_DONE);
if (more_results_exist(buffer))
if (more)
{
/** The server will send more resultsets */
LOG_RS(backend, REPLY_STATE_START);
@ -1183,10 +1125,6 @@ static void clientReply(MXS_ROUTER *instance,
GWBUF *writebuf,
DCB *backend_dcb)
{
ss_dassert((GWBUF_IS_CONTIGUOUS(writebuf) &&
MYSQL_GET_PAYLOAD_LEN(GWBUF_DATA(writebuf)) +
MYSQL_HEADER_LEN == gwbuf_length(writebuf)) ||
GWBUF_IS_COLLECTED_RESULT(writebuf));
RWSplitSession *rses = (RWSplitSession *)router_session;
DCB *client_dcb = backend_dcb->session->client_dcb;
CHK_CLIENT_RSES(rses);
@ -1280,7 +1218,7 @@ static void clientReply(MXS_ROUTER *instance,
*/
static uint64_t getCapabilities(MXS_ROUTER* instance)
{
return RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | RCAP_TYPE_STMT_OUTPUT;
return RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | RCAP_TYPE_PACKET_OUTPUT;
}
/**
@ -1431,7 +1369,7 @@ MXS_MODULE *MXS_CREATE_MODULE()
MXS_MODULE_API_ROUTER, MXS_MODULE_GA, MXS_ROUTER_VERSION,
"A Read/Write splitting router for enhancement read scalability",
"V1.1.0",
RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | RCAP_TYPE_STMT_OUTPUT,
RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | RCAP_TYPE_PACKET_OUTPUT,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */