From fbc1a7d44bafe083a1748ee6cf6ec98bad3772a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 21 Sep 2017 20:40:51 +0300 Subject: [PATCH] Fix handling of multi-packet queries in readwritesplit If a prepared statement sends large amounts of data, the target server where the data is sent will be tracked. The tracked target was not reset after a multi-packet query was completed and the target itself was used to check whether the session was processing a multi-packet query. Changed the check to use the boolean variable instead of the target and added a reset of the tracked target after a multi-packet query was completed. --- .../routing/readwritesplit/rwsplit_mysql.cc | 6 +++++- .../routing/readwritesplit/rwsplit_route_stmt.cc | 14 ++++++++++++-- .../routing/readwritesplit/rwsplit_session_cmd.cc | 1 + .../routing/readwritesplit/rwsplitsession.cc | 5 +++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/server/modules/routing/readwritesplit/rwsplit_mysql.cc b/server/modules/routing/readwritesplit/rwsplit_mysql.cc index 3b66b78d6..21d5a9229 100644 --- a/server/modules/routing/readwritesplit/rwsplit_mysql.cc +++ b/server/modules/routing/readwritesplit/rwsplit_mysql.cc @@ -150,7 +150,11 @@ is_packet_a_query(int packet_type) void log_transaction_status(RWSplitSession *rses, GWBUF *querybuf, uint32_t qtype) { - if (rses->load_data_state == LOAD_DATA_INACTIVE) + if (rses->large_query) + { + MXS_INFO("> Processing large request with more than 2^24 bytes of data"); + } + else if (rses->load_data_state == LOAD_DATA_INACTIVE) { uint8_t *packet = GWBUF_DATA(querybuf); unsigned char command = packet[4]; diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index d3df7421e..bd35eb27a 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -182,7 +182,7 @@ bool route_single_stmt(RWSplit *inst, RWSplitSession *rses, GWBUF *querybuf, con uint8_t command = info.command; uint32_t qtype = info.type; route_target_t route_target = info.target; - bool not_locked_to_master = !rses->prev_target && + bool not_locked_to_master = !rses->large_query && (!rses->target_node || rses->target_node != rses->current_master); if (not_locked_to_master && is_ps_command(command)) @@ -1091,7 +1091,12 @@ static inline bool query_creates_reply(uint8_t cmd) static inline bool is_large_query(GWBUF* buf) { uint32_t buflen = gwbuf_length(buf); + + // The buffer should contain at most (2^24 - 1) + 4 bytes ... ss_dassert(buflen <= MYSQL_HEADER_LEN + GW_MYSQL_MAX_PACKET_LEN); + // ... and the payload should be buflen - 4 bytes + ss_dassert(MYSQL_GET_PAYLOAD_LEN(GWBUF_DATA(buf)) == buflen - MYSQL_HEADER_LEN); + return buflen == MYSQL_HEADER_LEN + GW_MYSQL_MAX_PACKET_LEN; } @@ -1165,11 +1170,16 @@ bool handle_got_target(RWSplit *inst, RWSplitSession *rses, } } - /** Store the previous target if we're processing a multi-packet query */ if ((rses->large_query = large_query)) { + /** Store the previous target as we're processing a multi-packet query */ rses->prev_target = target; } + else + { + /** Otherwise reset it so we know the query is complete */ + rses->prev_target.reset(); + } /** * If a READ ONLY transaction is ending set forced_node to NULL diff --git a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc index 035e65b85..63d910c04 100644 --- a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc +++ b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc @@ -63,6 +63,7 @@ void process_sescmd_response(RWSplitSession* rses, SRWBackend& backend, if (command == MXS_COM_STMT_PREPARE) { /** Map the returned response to the internal ID */ + MXS_INFO("PS ID %u maps to internal ID %lu", resp.id, id); rses->ps_handles[resp.id] = id; } } diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index df02ee63c..737f698f9 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -108,6 +108,11 @@ uint32_t get_internal_ps_id(RWSplitSession* rses, GWBUF* buffer) { rval = it->second; } + else + { + MXS_WARNING("Client requests unknown prepared statement ID '%u' that " + "does not map to an internal ID", id); + } return rval; }