MXS-852: Track target of last COM_STMT_EXECUTE

Tracking of the node where the last COM_STMT_EXECUTE was sent allows
routing of all following COM_STMT_FETCH to the same node. This is required
for cursors to work.

MariaDB/MySQL does not support multiple active cursors so the
COM_STMT_FETCH will always refer to the latest COM_STMT_EXECUTE and using
a different ID goes against the protocol. If/when the support for multiple
active cursors is added, the tracking should be done for each
COM_STMT_EXECUTE statement. This should be relatively easily to achieve
but currently it is unnecessary.
This commit is contained in:
Markus Mäkelä
2017-06-22 15:18:29 +03:00
parent 52b7fb9340
commit d0b8ccd6b8
3 changed files with 28 additions and 5 deletions

View File

@ -311,6 +311,7 @@ struct ROUTER_CLIENT_SES
SRWBackendList backends; /**< List of backend servers */ SRWBackendList backends; /**< List of backend servers */
SRWBackend current_master; /**< Current master server */ SRWBackend current_master; /**< Current master server */
SRWBackend target_node; /**< The currently locked target node */ SRWBackend target_node; /**< The currently locked target node */
SRWBackend last_exec_target; /**< Node where the latest COM_STMT_EXECUTE was sent */
rwsplit_config_t rses_config; /**< copied config info from router instance */ rwsplit_config_t rses_config; /**< copied config info from router instance */
int rses_nbackends; int rses_nbackends;
enum ld_state load_data_state; /**< Current load data state */ enum ld_state load_data_state; /**< Current load data state */

View File

@ -70,7 +70,7 @@ void handle_multi_temp_and_load(ROUTER_CLIENT_SES *rses, GWBUF *querybuf,
uint8_t packet_type, uint32_t *qtype); uint8_t packet_type, uint32_t *qtype);
SRWBackend handle_hinted_target(ROUTER_CLIENT_SES *rses, GWBUF *querybuf, SRWBackend handle_hinted_target(ROUTER_CLIENT_SES *rses, GWBUF *querybuf,
route_target_t route_target); route_target_t route_target);
SRWBackend handle_slave_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses); SRWBackend handle_slave_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses, uint8_t cmd);
bool handle_master_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses, bool handle_master_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,
SRWBackend* dest); SRWBackend* dest);
bool handle_got_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses, bool handle_got_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,

View File

@ -210,7 +210,7 @@ bool route_single_stmt(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,
} }
else if (TARGET_IS_SLAVE(route_target)) else if (TARGET_IS_SLAVE(route_target))
{ {
if ((target = handle_slave_is_target(inst, rses))) if ((target = handle_slave_is_target(inst, rses, command)))
{ {
succp = true; succp = true;
store_stmt = rses->rses_config.retry_failed_reads; store_stmt = rses->rses_config.retry_failed_reads;
@ -231,7 +231,16 @@ bool route_single_stmt(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,
if (target && succp) /*< Have DCB of the target backend */ if (target && succp) /*< Have DCB of the target backend */
{ {
ss_dassert(!store_stmt || TARGET_IS_SLAVE(route_target)); ss_dassert(!store_stmt || TARGET_IS_SLAVE(route_target));
handle_got_target(inst, rses, querybuf, target, store_stmt); succp = handle_got_target(inst, rses, querybuf, target, store_stmt);
if (succp && command == MYSQL_COM_STMT_EXECUTE)
{
/** Track where the target of the last COM_STMT_EXECUTE. This
* information is used to route all COM_STMT_FETCH commands
* to the same server where the COM_STMT_EXECUTE was done. */
rses->last_exec_target = target;
MXS_INFO("COM_STMT_EXECUTE on %s", target->uri());
}
} }
} }
@ -919,10 +928,23 @@ SRWBackend handle_hinted_target(ROUTER_CLIENT_SES *rses, GWBUF *querybuf,
* *
* @return bool - true if succeeded, false otherwise * @return bool - true if succeeded, false otherwise
*/ */
SRWBackend handle_slave_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses) SRWBackend handle_slave_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,
uint8_t cmd)
{ {
int rlag_max = rses_get_max_replication_lag(rses); int rlag_max = rses_get_max_replication_lag(rses);
SRWBackend target = get_target_backend(rses, BE_SLAVE, NULL, rlag_max); SRWBackend target;
if (cmd == MYSQL_COM_STMT_FETCH && rses->last_exec_target)
{
/** The COM_STMT_FETCH must be executed on the same server as the
* COM_STMT_EXECUTE was executed on */
target = rses->last_exec_target;
MXS_INFO("COM_STMT_FETCH on %s", target->uri());
}
else
{
target = get_target_backend(rses, BE_SLAVE, NULL, rlag_max);
}
if (target) if (target)
{ {