diff --git a/include/maxscale/hint.h b/include/maxscale/hint.h index c7b5397ab..ad1c997f5 100644 --- a/include/maxscale/hint.h +++ b/include/maxscale/hint.h @@ -31,6 +31,7 @@ typedef enum HINT_ROUTE_TO_NAMED_SERVER, HINT_ROUTE_TO_UPTODATE_SERVER, /*< not supported by RWSplit and HintRouter */ HINT_ROUTE_TO_ALL, /*< not supported by RWSplit, supported by HintRouter */ + HINT_ROUTE_TO_LAST_USED, HINT_PARAMETER } HINT_TYPE; diff --git a/include/maxscale/queryclassifier.hh b/include/maxscale/queryclassifier.hh index c366f4282..a1d62a1df 100644 --- a/include/maxscale/queryclassifier.hh +++ b/include/maxscale/queryclassifier.hh @@ -117,7 +117,8 @@ public: TARGET_SLAVE = 0x02, TARGET_NAMED_SERVER = 0x04, TARGET_ALL = 0x08, - TARGET_RLAG_MAX = 0x10 + TARGET_RLAG_MAX = 0x10, + TARGET_LAST_USED = 0x20 }; static bool target_is_master(uint32_t t) @@ -145,6 +146,11 @@ public: return (t & TARGET_RLAG_MAX); } + static bool target_is_last_used(uint32_t t) + { + return (t & TARGET_LAST_USED); + } + enum current_target_t { CURRENT_TARGET_UNDEFINED, /**< Current target has not been set. */ diff --git a/server/core/queryclassifier.cc b/server/core/queryclassifier.cc index e55be8520..7c2d7634a 100644 --- a/server/core/queryclassifier.cc +++ b/server/core/queryclassifier.cc @@ -530,6 +530,11 @@ uint32_t QueryClassifier::get_route_target(uint8_t command, uint32_t qtype, HINT ss_dassert(false); break; + case HINT_ROUTE_TO_LAST_USED: + MXS_DEBUG("Hint: route to last used"); + target = TARGET_LAST_USED; + break; + case HINT_PARAMETER: if (strncasecmp((char*)pHint->data, "max_slave_replication_lag", strlen("max_slave_replication_lag")) == 0) diff --git a/server/modules/filter/hintfilter/hintparser.cc b/server/modules/filter/hintfilter/hintparser.cc index db61b5627..16bd83379 100644 --- a/server/modules/filter/hintfilter/hintparser.cc +++ b/server/modules/filter/hintfilter/hintparser.cc @@ -49,6 +49,7 @@ static struct { "master", TOK_MASTER}, { "slave", TOK_SLAVE}, { "server", TOK_SERVER}, + { "last" , TOK_LAST}, { NULL, static_cast(0)} }; @@ -334,6 +335,12 @@ hint_parser(HINT_SESSION *session, GWBUF *request) rval = hint_create_route(rval, HINT_ROUTE_TO_SLAVE, NULL); break; + + case TOK_LAST: + rval = hint_create_route(rval, + HINT_ROUTE_TO_LAST_USED, NULL); + break; + case TOK_SERVER: state = HS_ROUTE_SERVER; break; diff --git a/server/modules/filter/hintfilter/mysqlhint.h b/server/modules/filter/hintfilter/mysqlhint.h index d1efc1fb6..c47e51557 100644 --- a/server/modules/filter/hintfilter/mysqlhint.h +++ b/server/modules/filter/hintfilter/mysqlhint.h @@ -40,6 +40,7 @@ typedef enum TOK_MASTER, TOK_SLAVE, TOK_SERVER, + TOK_LAST, TOK_LINEBRK, TOK_END } TOKEN_VALUE; diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 9bf706958..bd5d4e08a 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -281,6 +281,13 @@ bool RWSplitSession::route_single_stmt(GWBUF *querybuf) succp = true; } } + else if (TARGET_IS_LAST_USED(route_target)) + { + if ((target = get_last_used_backend())) + { + succp = true; + } + } else if (TARGET_IS_SLAVE(route_target)) { if ((target = handle_slave_is_target(command, stmt_id))) @@ -644,6 +651,11 @@ SRWBackend RWSplitSession::get_master_backend() return rval; } +SRWBackend RWSplitSession::get_last_used_backend() +{ + return m_prev_target ? m_prev_target : get_master_backend(); +} + /** * Provide the router with a reference to a suitable backend * diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index 521774c51..02b25d806 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -993,6 +993,7 @@ bool RWSplitSession::supports_hint(HINT_TYPE hint_type) const case HINT_ROUTE_TO_MASTER: case HINT_ROUTE_TO_SLAVE: case HINT_ROUTE_TO_NAMED_SERVER: + case HINT_ROUTE_TO_LAST_USED: case HINT_PARAMETER: break; diff --git a/server/modules/routing/readwritesplit/rwsplitsession.hh b/server/modules/routing/readwritesplit/rwsplitsession.hh index bbc1b2d82..36d0d441f 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.hh +++ b/server/modules/routing/readwritesplit/rwsplitsession.hh @@ -27,6 +27,7 @@ #define TARGET_IS_NAMED_SERVER(t) maxscale::QueryClassifier::target_is_named_server(t) #define TARGET_IS_ALL(t) maxscale::QueryClassifier::target_is_all(t) #define TARGET_IS_RLAG_MAX(t) maxscale::QueryClassifier::target_is_rlag_max(t) +#define TARGET_IS_LAST_USED(t) maxscale::QueryClassifier::target_is_last_used(t) typedef std::map ClientHandleMap; /** External ID to internal ID */ @@ -57,6 +58,7 @@ public: TARGET_NAMED_SERVER = maxscale::QueryClassifier::TARGET_NAMED_SERVER, TARGET_ALL = maxscale::QueryClassifier::TARGET_ALL, TARGET_RLAG_MAX = maxscale::QueryClassifier::TARGET_RLAG_MAX, + TARGET_LAST_USED = maxscale::QueryClassifier::TARGET_LAST_USED, }; enum otrx_state @@ -174,6 +176,7 @@ private: mxs::SRWBackend get_hinted_backend(char *name); mxs::SRWBackend get_slave_backend(int max_rlag); mxs::SRWBackend get_master_backend(); + mxs::SRWBackend get_last_used_backend(); mxs::SRWBackend get_target_backend(backend_type_t btype, char *name, int max_rlag); bool handle_target_is_all(route_target_t route_target, GWBUF *querybuf,