diff --git a/Documentation/About/Limitations.md b/Documentation/About/Limitations.md index fb3a5bf29..be418ed87 100644 --- a/Documentation/About/Limitations.md +++ b/Documentation/About/Limitations.md @@ -32,6 +32,12 @@ In master-slave replication cluster also read-only queries are routed to master * statement includes a stored procedure, or an UDF call +If the client enables and executes multi-statements, they will be routed to +the master. All future queries will also be routed to the master to guarantee +a consistent session state after the multi-statement query. This behavior can +be controlled with the `strict_multi_stmt` router option. For more information, +read the [ReadWriteSplit](../Routers/ReadWriteSplit.md) router documentation. + ### Limitations in client session handling Some of the queries that client sends are routed to all backends instead of sending them just to one of server. These queries include `USE ` and `SET autocommit=0` among many others. Readwritesplit sends a copy of these queries to each backend server and forwards the master's reply to the client. Below is a list of MySQL commands which are classified as session commands : diff --git a/Documentation/Routers/ReadWriteSplit.md b/Documentation/Routers/ReadWriteSplit.md index 83076955d..8fca0a006 100644 --- a/Documentation/Routers/ReadWriteSplit.md +++ b/Documentation/Routers/ReadWriteSplit.md @@ -143,6 +143,22 @@ disable_sescmd_history=true master_accept_reads=true ``` +### `strict_multi_stmt` + +When a client executes a multistatement query, all queries after that will be routed to +the master to guarantee a consistent session state. This behavior can be controlled with +the **`strict_multi_stmt`** router option. This option is enabled by default. + +If set to false, queries are routed normally after a multistatement query. **Warning**, this +can cause false data to be read from the slaves if the multistatement query modifies +the session state. Only disable the strict mode if you know that no changes to the session +state will be made inside the multistatement queries. + +``` +# Disable strict multistatement mode +strict_multi_stmt=false +``` + ## Routing hints The readwritesplit router supports routing hints. For a detailed guide on hint syntax and functionality, please read [this](../Reference/Hint-Syntax.md) document. diff --git a/server/modules/include/readwritesplit.h b/server/modules/include/readwritesplit.h index d4786e4d0..99c9e2186 100644 --- a/server/modules/include/readwritesplit.h +++ b/server/modules/include/readwritesplit.h @@ -252,6 +252,8 @@ typedef struct rwsplit_config_st int rw_max_sescmd_history_size; bool rw_disable_sescmd_hist; bool rw_master_reads; /*< Use master for reads */ + bool rw_strict_multi_stmt; /*< Force non-multistatement queries to be routed + * to the master after a multistatement query. */ } rwsplit_config_t; #if defined(PREP_STMT_CACHING) diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index 241ed602a..2990e69d9 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -696,7 +696,10 @@ createInstance(SERVICE *service, char **options) */ router->bitmask = 0; router->bitvalue = 0; - + + /** Enable strict multistatement handling by default */ + router->rwsplit_config.rw_strict_multi_stmt = true; + /** Call this before refreshInstance */ if (options) { @@ -1384,7 +1387,7 @@ static route_target_t get_route_target(ROUTER_CLIENT_SES *rses, 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) + if (rses->rses_config.rw_strict_multi_stmt && rses->forced_node == rses->rses_master_ref) { target = TARGET_MASTER; } @@ -4640,6 +4643,10 @@ static void rwsplit_process_router_options( { router->rwsplit_config.rw_master_reads = config_truth_value(value); } + else if(strcmp(options[i],"strict_multi_stmt") == 0) + { + router->rwsplit_config.rw_strict_multi_stmt = config_truth_value(value); + } } } /*< for */ }