MXS-497: Multi-statement queries are always routed to the master
This will prevent the routing of queries that modify data to the slaves. In the future a more intricate solution can done where all the statements are parsed and the destination is resolved based on the actual contents.
This commit is contained in:
parent
b88d66357e
commit
ac007fa8f5
@ -67,5 +67,6 @@ GWBUF* modutil_create_mysql_err_msg(int packet_number,
|
||||
const char *msg);
|
||||
int modutil_count_signal_packets(GWBUF*,int,int,int*);
|
||||
mxs_pcre2_result_t modutil_mysql_wildcard_match(const char* pattern, const char* string);
|
||||
void* strnchr_esc(char* ptr, char c, int len);
|
||||
|
||||
#endif
|
||||
|
@ -298,6 +298,7 @@ struct router_client_session {
|
||||
uint64_t rses_load_data_sent; /*< How much data has been sent */
|
||||
DCB* client_dcb;
|
||||
int pos_generator;
|
||||
backend_ref_t *forced_node; /*< Current server where all queries should be sent */
|
||||
#if defined(PREP_STMT_CACHING)
|
||||
HASHTABLE* rses_prep_stmt[2];
|
||||
#endif
|
||||
|
@ -102,13 +102,6 @@ static int rses_get_max_replication_lag(ROUTER_CLIENT_SES* rses);
|
||||
static backend_ref_t* get_bref_from_dcb(ROUTER_CLIENT_SES* rses, DCB* dcb);
|
||||
static DCB* rses_get_client_dcb(ROUTER_CLIENT_SES* rses);
|
||||
|
||||
static route_target_t get_route_target (
|
||||
qc_query_type_t qtype,
|
||||
bool trx_active,
|
||||
bool load_active,
|
||||
target_t use_sql_variables_in,
|
||||
HINT* hint);
|
||||
|
||||
static backend_ref_t* check_candidate_bref(
|
||||
backend_ref_t* candidate_bref,
|
||||
backend_ref_t* new_bref,
|
||||
@ -834,6 +827,7 @@ static void* newSession(
|
||||
client_rses->rses_autocommit_enabled = true;
|
||||
client_rses->rses_transaction_active = false;
|
||||
client_rses->have_tmp_tables = false;
|
||||
client_rses->forced_node = NULL;
|
||||
|
||||
router_nservers = router_get_servercount(router);
|
||||
|
||||
@ -1382,18 +1376,22 @@ static backend_ref_t* check_candidate_bref(
|
||||
* @return bitfield including the routing target, or the target server name
|
||||
* if the query would otherwise be routed to slave.
|
||||
*/
|
||||
static route_target_t get_route_target (
|
||||
qc_query_type_t qtype,
|
||||
bool trx_active,
|
||||
bool load_active,
|
||||
target_t use_sql_variables_in,
|
||||
HINT* hint)
|
||||
static route_target_t get_route_target(ROUTER_CLIENT_SES *rses,
|
||||
qc_query_type_t qtype, HINT *hint)
|
||||
{
|
||||
route_target_t target = TARGET_UNDEFINED;
|
||||
bool trx_active = rses->rses_transaction_active;
|
||||
bool load_active = rses->rses_load_active;
|
||||
target_t use_sql_variables_in = rses->rses_config.rw_use_sql_variables_in;
|
||||
route_target_t target = TARGET_UNDEFINED;
|
||||
|
||||
if (rses->forced_node == rses->rses_master_ref)
|
||||
{
|
||||
target = TARGET_MASTER;
|
||||
}
|
||||
/**
|
||||
* These queries are not affected by hints
|
||||
*/
|
||||
if (!load_active && (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||
else if (!load_active && (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||
/** Configured to allow writing variables to all nodes */
|
||||
(use_sql_variables_in == TYPE_ALL &&
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE)) ||
|
||||
@ -2150,7 +2148,29 @@ static bool route_single_stmt(
|
||||
{
|
||||
succp = false;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
/** Check for multi-statement queries. We assume here that the client
|
||||
* protocol is MySQLClient.
|
||||
* TODO: add warnings when incompatible protocols are used */
|
||||
MySQLProtocol *proto = (MySQLProtocol*)rses->client_dcb->protocol;
|
||||
if (proto->client_capabilities & GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS &&
|
||||
packet_type == MYSQL_COM_QUERY && rses->forced_node != rses->rses_master_ref)
|
||||
{
|
||||
for (GWBUF *buf = querybuf; buf != NULL; buf = buf->next)
|
||||
{
|
||||
if (strnchr_esc(GWBUF_DATA(buf), ';', GWBUF_LENGTH(buf)))
|
||||
{
|
||||
/** It is possible that the session state is modified inside
|
||||
* the multi-statement query which would leave any slave sessions
|
||||
* in an inconsistent state. Due to this, for the duration of
|
||||
* this session, all queries will be sent to the master. */
|
||||
rses->forced_node = rses->rses_master_ref;
|
||||
MXS_INFO("Multi-statement query, routing all future queries to master.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query has anything to do with temporary tables.
|
||||
*/
|
||||
@ -2269,11 +2289,7 @@ static bool route_single_stmt(
|
||||
* - route primarily according to the hints and if they failed,
|
||||
* eventually to master
|
||||
*/
|
||||
route_target = get_route_target(qtype,
|
||||
rses->rses_transaction_active,
|
||||
rses->rses_load_active,
|
||||
rses->rses_config.rw_use_sql_variables_in,
|
||||
querybuf->hint);
|
||||
route_target = get_route_target(rses, qtype, querybuf->hint);
|
||||
|
||||
if (TARGET_IS_ALL(route_target))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user