diff --git a/server/modules/routing/schemarouter/schemarouter.cc b/server/modules/routing/schemarouter/schemarouter.cc index 964de6ff8..68c2bf3e1 100644 --- a/server/modules/routing/schemarouter/schemarouter.cc +++ b/server/modules/routing/schemarouter/schemarouter.cc @@ -11,7 +11,7 @@ * Public License. */ -#include "schemarouter.h" +#include "schemarouter.hh" #include #include @@ -69,7 +69,7 @@ static void handle_error_reply_client(MXS_SESSION* ses, SCHEMAROUTER_SESSION* rses, DCB* backend_dcb, GWBUF* errmsg); -bool change_current_db(char* dest, Shard& shard, GWBUF* buf); +bool change_current_db(string& dest, Shard& shard, GWBUF* buf); bool extract_database(GWBUF* buf, char* str); bool detect_show_shards(GWBUF* query); @@ -286,8 +286,8 @@ int gen_databaselist(SCHEMAROUTER* inst, SCHEMAROUTER_SESSION* session) session->rses_backend_ref[i].n_mapping_eof = 0; } - session->init |= INIT_MAPPING; - session->init &= ~INIT_UNINT; + session->state |= INIT_MAPPING; + session->state &= ~INIT_UNINT; len = strlen(query) + 1; buffer = gwbuf_alloc(len + 4); uint8_t *data = GWBUF_DATA(buffer); @@ -400,7 +400,7 @@ SERVER* get_shard_target(SCHEMAROUTER* router, if (rval) { MXS_INFO("SHOW TABLES query, current database '%s' on server '%s'", - client->current_db, rval->unique_name); + client->current_db.c_str(), rval->unique_name); } } else @@ -421,7 +421,7 @@ SERVER* get_shard_target(SCHEMAROUTER* router, } } - if (rval == NULL && !has_dbs && client->current_db[0]) + if (rval == NULL && !has_dbs && client->current_db.length()) { /** * If the target name has not been found and the session has an @@ -433,7 +433,7 @@ SERVER* get_shard_target(SCHEMAROUTER* router, if (rval) { MXS_INFO("Using active database '%s' on '%s'", - client->current_db, rval->unique_name); + client->current_db.c_str(), rval->unique_name); } } } @@ -464,7 +464,7 @@ static bool get_shard_dcb(DCB** p_dcb, int i; bool succp = false; - CHK_CLIENT_RSES(rses); + ss_dassert(p_dcb != NULL && *(p_dcb) == NULL); if (p_dcb == NULL || name == NULL) @@ -866,7 +866,6 @@ static bool execute_sescmd_in_backend(backend_ref_t* backend_ref) DCB *dcb = backend_ref->bref_dcb; CHK_DCB(dcb); - CHK_BACKEND_REF(backend_ref); int rc = 0; @@ -925,7 +924,6 @@ static bool route_session_write(SCHEMAROUTER_SESSION* router_cli_ses, MXS_INFO("Session write, routing to all servers."); atomic_add(&router_cli_ses->stats.longest_sescmd, 1); - atomic_add(&router_cli_ses->n_sescmd, 1); /** Increment the session command count */ ++router_cli_ses->sent_sescmd; @@ -998,7 +996,7 @@ static void handle_error_reply_client(MXS_SESSION* ses, if (bref) { - CHK_BACKEND_REF(bref); + bref_clear_state(bref, BREF_IN_USE); bref_set_state(bref, BREF_CLOSED); } @@ -1063,7 +1061,7 @@ static bool handle_error_new_connection(SCHEMAROUTER* inst, return false; } - CHK_BACKEND_REF(bref); + /** * If query was sent through the bref and it is waiting for reply from @@ -1095,7 +1093,7 @@ static backend_ref_t* get_bref_from_dcb(SCHEMAROUTER_SESSION *rses, DCB *dcb) { CHK_DCB(dcb); - CHK_CLIENT_RSES(rses); + for (int i = 0; i < rses->rses_nbackends; i++) { @@ -1230,7 +1228,7 @@ bool handle_default_db(SCHEMAROUTER_SESSION *router_cli_ses) /* Send a COM_INIT_DB packet to the server with the right database * and set it as the client's active database */ - unsigned int qlen = strlen(router_cli_ses->connect_db); + unsigned int qlen = router_cli_ses->connect_db.length(); GWBUF* buffer = gwbuf_alloc(qlen + 5); if (buffer) @@ -1240,14 +1238,14 @@ bool handle_default_db(SCHEMAROUTER_SESSION *router_cli_ses) gwbuf_set_type(buffer, GWBUF_TYPE_MYSQL); data[3] = 0x0; data[4] = 0x2; - memcpy(data + 5, router_cli_ses->connect_db, qlen); + memcpy(data + 5, router_cli_ses->connect_db.c_str(), qlen); DCB* dcb = NULL; if (get_shard_dcb(&dcb, router_cli_ses, target->unique_name)) { dcb->func.write(dcb, buffer); MXS_DEBUG("USE '%s' sent to %s for session %p", - router_cli_ses->connect_db, + router_cli_ses->connect_db.c_str(), target->unique_name, router_cli_ses->rses_client_dcb->session); rval = true; @@ -1265,10 +1263,9 @@ bool handle_default_db(SCHEMAROUTER_SESSION *router_cli_ses) else { /** Unknown database, hang up on the client*/ - MXS_INFO("Connecting to a non-existent database '%s'", - router_cli_ses->connect_db); + MXS_INFO("Connecting to a non-existent database '%s'", router_cli_ses->connect_db.c_str()); char errmsg[128 + MYSQL_DATABASE_MAXLEN + 1]; - sprintf(errmsg, "Unknown database '%s'", router_cli_ses->connect_db); + sprintf(errmsg, "Unknown database '%s'", router_cli_ses->connect_db.c_str()); if (router_cli_ses->rses_config.debug) { sprintf(errmsg + strlen(errmsg), " ([%lu]: DB not found on connect)", @@ -1342,7 +1339,7 @@ int inspect_backend_mapping_states(SCHEMAROUTER_SESSION *router_cli_ses, { DCB* client_dcb = NULL; - if ((router_cli_ses->init & INIT_FAILED) == 0) + if ((router_cli_ses->state & INIT_FAILED) == 0) { if (rc == SHOWDB_DUPLICATE_DATABASES) { @@ -1357,7 +1354,7 @@ int inspect_backend_mapping_states(SCHEMAROUTER_SESSION *router_cli_ses, /** This is the first response to the database mapping which * has duplicate database conflict. Set the initialization bitmask * to INIT_FAILED */ - router_cli_ses->init |= INIT_FAILED; + router_cli_ses->state |= INIT_FAILED; /** Send the client an error about duplicate databases * if there is a queued query from the client. */ @@ -1500,7 +1497,7 @@ void create_error_reply(char* fail_str, DCB* dcb) * @return true if new database is set, false if non-existent database was tried * to be set */ -bool change_current_db(char* dest, Shard& shard, GWBUF* buf) +bool change_current_db(string& dest, Shard& shard, GWBUF* buf) { bool succp = false; char db[MYSQL_DATABASE_MAXLEN + 1]; @@ -1520,7 +1517,7 @@ bool change_current_db(char* dest, Shard& shard, GWBUF* buf) if (target) { - strcpy(dest, db); + dest = db; MXS_INFO("change_current_db: database is on server: '%s'.", target->unique_name); succp = true; } @@ -1557,7 +1554,6 @@ static MXS_ROUTER* do_createInstance(SERVICE *service, char **options) router->ignored_dbs.insert("information_schema"); router->ignored_dbs.insert("performance_schema"); router->service = service; - router->schemarouter_config.last_refresh = time(NULL); router->stats.longest_sescmd = 0; router->stats.n_hist_exceeded = 0; router->stats.n_queries = 0; @@ -1729,33 +1725,26 @@ static MXS_ROUTER_SESSION* do_newSession(MXS_ROUTER* router_inst, MXS_SESSION* s SCHEMAROUTER* router = (SCHEMAROUTER*)router_inst; -#if defined(SS_DEBUG) - client_rses->rses_chk_top = CHK_NUM_ROUTER_SES; - client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES; -#endif + client_rses->router = router; - client_rses->rses_mysql_session = (MYSQL_session*)session->client_dcb->data; client_rses->rses_client_dcb = (DCB*)session->client_dcb; client_rses->queue = NULL; + client_rses->closed = false; + client_rses->sent_sescmd = 0; + client_rses->replied_sescmd = 0; + client_rses->shardmap = router->shard_manager.get_shard(session->client_dcb->user, router->schemarouter_config.refresh_min_interval); memcpy(&client_rses->rses_config, &router->schemarouter_config, sizeof(schemarouter_config_t)); - client_rses->n_sescmd = 0; - client_rses->rses_config.last_refresh = time(NULL); - client_rses->closed = false; if (using_db) { - client_rses->init |= INIT_USE_DB; + client_rses->state |= INIT_USE_DB; } /** * Set defaults to session variables. */ - client_rses->rses_autocommit_enabled = true; - client_rses->rses_transaction_active = false; - client_rses->sent_sescmd = 0; - client_rses->replied_sescmd = 0; /** * Instead of calling this, ensure that there is at least one @@ -1781,10 +1770,6 @@ static MXS_ROUTER_SESSION* do_newSession(MXS_ROUTER* router_inst, MXS_SESSION* s { if (ref->active) { -#if defined(SS_DEBUG) - backend_ref[i].bref_chk_top = CHK_NUM_BACKEND_REF; - backend_ref[i].bref_chk_tail = CHK_NUM_BACKEND_REF; -#endif backend_ref[i].bref_state = 0; backend_ref[i].n_mapping_eof = 0; backend_ref[i].map_queue = NULL; @@ -1818,7 +1803,7 @@ static MXS_ROUTER_SESSION* do_newSession(MXS_ROUTER* router_inst, MXS_SESSION* s if (db[0]) { /* Store the database the client is connecting to */ - snprintf(client_rses->connect_db, MYSQL_DATABASE_MAXLEN + 1, "%s", db); + client_rses->connect_db = db; } atomic_add(&router->stats.sessions, 1); @@ -1845,7 +1830,7 @@ static MXS_ROUTER_SESSION* newSession(MXS_ROUTER* router_inst, MXS_SESSION* sess static void do_closeSession(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_session) { SCHEMAROUTER_SESSION *router_cli_ses = (SCHEMAROUTER_SESSION *)router_session; - CHK_CLIENT_RSES(router_cli_ses); + ss_dassert(!router_cli_ses->closed); /** @@ -1971,7 +1956,7 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio bool succp = false; char db[MYSQL_DATABASE_MAXLEN + 1]; char errbuf[26 + MYSQL_DATABASE_MAXLEN]; - CHK_CLIENT_RSES(router_cli_ses); + SERVER* target = NULL; ss_dassert(!GWBUF_IS_TYPE_UNDEFINED(querybuf)); @@ -1993,7 +1978,7 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio * to store the query. Once the databases have been mapped and/or the * default database is taken into use we can send the query forward. */ - if (router_cli_ses->init & (INIT_MAPPING | INIT_USE_DB)) + if (router_cli_ses->state & (INIT_MAPPING | INIT_USE_DB)) { int init_rval = 1; char* querystr = modutil_get_SQL(querybuf); @@ -2019,7 +2004,7 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio } - if (router_cli_ses->init == (INIT_READY | INIT_USE_DB)) + if (router_cli_ses->state == (INIT_READY | INIT_USE_DB)) { /** * This state is possible if a client connects with a default database @@ -2117,23 +2102,9 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio querybuf); if (!change_successful) { - time_t now = time(NULL); - if (router_cli_ses->rses_config.refresh_databases && - difftime(now, router_cli_ses->rses_config.last_refresh) > - router_cli_ses->rses_config.refresh_min_interval) - { - - router_cli_ses->rses_config.last_refresh = now; - router_cli_ses->queue = querybuf; - - // Reset the shard map by constructing a new Shard - router_cli_ses->shardmap = Shard(); - gen_databaselist(inst, router_cli_ses); - - return 1; - } extract_database(querybuf, db); snprintf(errbuf, 25 + MYSQL_DATABASE_MAXLEN, "Unknown database: %s", db); + if (router_cli_ses->rses_config.debug) { sprintf(errbuf + strlen(errbuf), @@ -2174,7 +2145,7 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio if (target) { MXS_INFO("INIT_DB for database '%s' on server '%s'", - router_cli_ses->current_db, target->unique_name); + router_cli_ses->current_db.c_str(), target->unique_name); route_target = TARGET_NAMED_SERVER; } else @@ -2216,9 +2187,9 @@ static int do_routeQuery(MXS_ROUTER* instance, MXS_ROUTER_SESSION* router_sessio if ((target == NULL && packet_type != MYSQL_COM_INIT_DB && - router_cli_ses->current_db[0] == '\0') || + router_cli_ses->current_db.length() == 0) || packet_type == MYSQL_COM_FIELD_LIST || - (router_cli_ses->current_db[0] != '\0')) + (router_cli_ses->current_db.length() == 0)) { /** * No current database and no databases in query or @@ -2439,7 +2410,7 @@ static void do_clientReply(MXS_ROUTER* instance, GWBUF* writebuf = buffer; SCHEMAROUTER_SESSION *router_cli_ses = (SCHEMAROUTER_SESSION *) router_session; - CHK_CLIENT_RSES(router_cli_ses); + /** * Lock router client session for secure read of router session members. @@ -2467,13 +2438,13 @@ static void do_clientReply(MXS_ROUTER* instance, " mapping [%s] queries queued [%s]", bref->bref_backend->server->unique_name, router_cli_ses->rses_client_dcb->session, - router_cli_ses->init & INIT_MAPPING ? "true" : "false", + router_cli_ses->state & INIT_MAPPING ? "true" : "false", router_cli_ses->queue == NULL ? "none" : router_cli_ses->queue->next ? "multiple" : "one"); - if (router_cli_ses->init & INIT_MAPPING) + if (router_cli_ses->state & INIT_MAPPING) { int rc = inspect_backend_mapping_states(router_cli_ses, bref, &writebuf); gwbuf_free(writebuf); @@ -2488,9 +2459,9 @@ static void do_clientReply(MXS_ROUTER* instance, * that is not in the hashtable. If the database is not found * then close the session. */ - router_cli_ses->init &= ~INIT_MAPPING; + router_cli_ses->state &= ~INIT_MAPPING; - if (router_cli_ses->init & INIT_USE_DB) + if (router_cli_ses->state & INIT_USE_DB) { bool success = handle_default_db(router_cli_ses); if (!success) @@ -2502,7 +2473,7 @@ static void do_clientReply(MXS_ROUTER* instance, if (router_cli_ses->queue) { - ss_dassert(router_cli_ses->init == INIT_READY); + ss_dassert(router_cli_ses->state == INIT_READY); route_queued_query(router_cli_ses); } MXS_DEBUG("session [%p] database map finished.", @@ -2516,14 +2487,14 @@ static void do_clientReply(MXS_ROUTER* instance, return; } - if (router_cli_ses->init & INIT_USE_DB) + if (router_cli_ses->state & INIT_USE_DB) { MXS_DEBUG("Reply to USE '%s' received for session %p", - router_cli_ses->connect_db, + router_cli_ses->connect_db.c_str(), router_cli_ses->rses_client_dcb->session); - router_cli_ses->init &= ~INIT_USE_DB; - strcpy(router_cli_ses->current_db, router_cli_ses->connect_db); - ss_dassert(router_cli_ses->init == INIT_READY); + router_cli_ses->state &= ~INIT_USE_DB; + router_cli_ses->current_db = router_cli_ses->connect_db; + ss_dassert(router_cli_ses->state == INIT_READY); if (router_cli_ses->queue) { @@ -2536,12 +2507,12 @@ static void do_clientReply(MXS_ROUTER* instance, if (router_cli_ses->queue) { - ss_dassert(router_cli_ses->init == INIT_READY); + ss_dassert(router_cli_ses->state == INIT_READY); route_queued_query(router_cli_ses); return; } - CHK_BACKEND_REF(bref); + /** * Active cursor means that reply is from session command @@ -2595,7 +2566,7 @@ static void do_clientReply(MXS_ROUTER* instance, if (writebuf != NULL && client_dcb != NULL) { unsigned char* cmd = (unsigned char*) writebuf->start; - int state = router_cli_ses->init; + int state = router_cli_ses->state; /** Write reply to client DCB */ MXS_INFO("returning reply [%s] " "state [%s] session [%p]", @@ -2690,7 +2661,6 @@ static void do_handleError(MXS_ROUTER* instance, ss_dassert(session && rses); CHK_SESSION(session); - CHK_CLIENT_RSES(rses); switch (action) { diff --git a/server/modules/routing/schemarouter/schemarouter.h b/server/modules/routing/schemarouter/schemarouter.h deleted file mode 100644 index 19a26bc53..000000000 --- a/server/modules/routing/schemarouter/schemarouter.h +++ /dev/null @@ -1,308 +0,0 @@ -#pragma once -#ifndef _SCHEMAROUTER_H -#define _SCHEMAROUTER_H -/* - * Copyright (c) 2016 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 2019-07-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2 or later of the General - * Public License. - */ - -/** - * @file schemarouter.h - The schemarouter router module header file - * - * @verbatim - * Revision History - * - * See GitHub https://github.com/mariadb-corporation/MaxScale - * - * @endverbatim - */ - -#define MXS_MODULE_NAME "schemarouter" - -#include - -#include -#include - -#include -#include -#include -#include - -#include "shard_map.hh" -#include "session_command.hh" - -MXS_BEGIN_DECLS - -/** - * Bitmask values for the router session's initialization. These values are used - * to prevent responses from internal commands being forwarded to the client. - */ -typedef enum init_mask -{ - INIT_READY = 0x0, - INIT_MAPPING = 0x1, - INIT_USE_DB = 0x02, - INIT_UNINT = 0x04, - INIT_FAILED = 0x08 -} init_mask_t; - -typedef enum showdb_response -{ - SHOWDB_FULL_RESPONSE, - SHOWDB_PARTIAL_RESPONSE, - SHOWDB_DUPLICATE_DATABASES, - SHOWDB_FATAL_ERROR -} showdb_response_t; - -/** - * The state of the backend server reference - */ -typedef enum bref_state -{ - BREF_IN_USE = 0x01, - BREF_WAITING_RESULT = 0x02, /*< for session commands only */ - BREF_QUERY_ACTIVE = 0x04, /*< for other queries */ - BREF_CLOSED = 0x08, - BREF_DB_MAPPED = 0x10 -} bref_state_t; - -#define BREF_IS_NOT_USED(s) ((s)->bref_state & ~BREF_IN_USE) -#define BREF_IS_IN_USE(s) ((s)->bref_state & BREF_IN_USE) -#define BREF_IS_WAITING_RESULT(s) ((s)->bref_num_result_wait > 0) -#define BREF_IS_QUERY_ACTIVE(s) ((s)->bref_state & BREF_QUERY_ACTIVE) -#define BREF_IS_CLOSED(s) ((s)->bref_state & BREF_CLOSED) -#define BREF_IS_MAPPED(s) ((s)->bref_mapped) - -#define SCHEMA_ERR_DUPLICATEDB 5000 -#define SCHEMA_ERRSTR_DUPLICATEDB "DUPDB" -#define SCHEMA_ERR_DBNOTFOUND 1049 -#define SCHEMA_ERRSTR_DBNOTFOUND "42000" -/** - * The type of the backend server - */ -typedef enum backend_type_t -{ - BE_UNDEFINED = -1, - BE_MASTER, - BE_JOINED = BE_MASTER, - BE_SLAVE, - BE_COUNT -} backend_type_t; - -struct schemarouter_instance; - -/** - * Route target types - */ -typedef enum -{ - TARGET_UNDEFINED = 0x00, - TARGET_MASTER = 0x01, - TARGET_SLAVE = 0x02, - TARGET_NAMED_SERVER = 0x04, - TARGET_ALL = 0x08, - TARGET_RLAG_MAX = 0x10, - TARGET_ANY = 0x20 -} route_target_t; - -#define TARGET_IS_UNDEFINED(t) (t == TARGET_UNDEFINED) -#define TARGET_IS_NAMED_SERVER(t) (t & TARGET_NAMED_SERVER) -#define TARGET_IS_ALL(t) (t & TARGET_ALL) -#define TARGET_IS_ANY(t) (t & TARGET_ANY) - -typedef struct schemarouter_session SCHEMAROUTER_SESSION; - -/** - * Router session properties - */ -typedef enum rses_property_type_t -{ - RSES_PROP_TYPE_UNDEFINED = -1, - RSES_PROP_TYPE_SESCMD = 0, - RSES_PROP_TYPE_FIRST = RSES_PROP_TYPE_SESCMD, - RSES_PROP_TYPE_TMPTABLES, - RSES_PROP_TYPE_LAST = RSES_PROP_TYPE_TMPTABLES, - RSES_PROP_TYPE_COUNT = RSES_PROP_TYPE_LAST + 1 -} rses_property_type_t; - -/** default values for rwsplit configuration parameters */ -#define CONFIG_MAX_SLAVE_CONN 1 -#define CONFIG_MAX_SLAVE_RLAG -1 /*< not used */ -#define CONFIG_SQL_VARIABLES_IN TYPE_ALL - -#define GET_SELECT_CRITERIA(s) \ - (strncmp(s,"LEAST_GLOBAL_CONNECTIONS", strlen("LEAST_GLOBAL_CONNECTIONS")) == 0 ? \ - LEAST_GLOBAL_CONNECTIONS : ( \ - strncmp(s,"LEAST_BEHIND_MASTER", strlen("LEAST_BEHIND_MASTER")) == 0 ? \ - LEAST_BEHIND_MASTER : ( \ - strncmp(s,"LEAST_ROUTER_CONNECTIONS", strlen("LEAST_ROUTER_CONNECTIONS")) == 0 ? \ - LEAST_ROUTER_CONNECTIONS : ( \ - strncmp(s,"LEAST_CURRENT_OPERATIONS", strlen("LEAST_CURRENT_OPERATIONS")) == 0 ? \ - LEAST_CURRENT_OPERATIONS : UNDEFINED_CRITERIA)))) - -/** - * Internal structure used to define the set of backend servers we are routing - * connections to. This provides the storage for routing module specific data - * that is required for each of the backend servers. - * - * Owned by router_instance, referenced by each routing session. - */ -typedef struct backend_st -{ -#if defined(SS_DEBUG) - skygw_chk_t be_chk_top; -#endif - SERVER* backend_server; /*< The server itself */ - - int weight; /*< Desired weighting on the - * load. Expressed in .1% - * increments - */ - struct stats - { - int queries; - } stats; -#if defined(SS_DEBUG) - skygw_chk_t be_chk_tail; -#endif -} BACKEND; - -/** - * Reference to BACKEND. - * - * Owned by router client session. - */ -typedef struct backend_ref_st -{ -#if defined(SS_DEBUG) - skygw_chk_t bref_chk_top; -#endif - int n_mapping_eof; - GWBUF* map_queue; - SERVER_REF* bref_backend; /*< Backend server */ - DCB* bref_dcb; /*< Backend DCB */ - int bref_state; /*< State of the backend */ - bool bref_mapped; /*< Whether the backend has been mapped */ - bool last_sescmd_replied; - int bref_num_result_wait; /*< Number of not yet received results */ - GWBUF* bref_pending_cmd; /*< For stmt which can't be routed due active sescmd execution */ - - SessionCommandList session_commands; /**< List of session commands that are - * to be executed on this backend server */ -#if defined(SS_DEBUG) - skygw_chk_t bref_chk_tail; -#endif -} backend_ref_t; - -/** - * Configuration values - */ -typedef struct schemarouter_config_st -{ - int rw_max_slave_conn_percent; - int rw_max_slave_conn_count; - mxs_target_t rw_use_sql_variables_in; - time_t last_refresh; /*< Last time the database list was refreshed */ - double refresh_min_interval; /*< Minimum required interval between refreshes of databases */ - bool refresh_databases; /*< Are databases refreshed when they are not found in the hashtable */ - bool debug; /*< Enable verbose debug messages to clients */ -} schemarouter_config_t; - -/** - * The statistics for this router instance - */ -typedef struct -{ - int n_queries; /*< Number of queries forwarded */ - int n_sescmd; /*< Number of session commands */ - int longest_sescmd; /*< Longest chain of stored session commands */ - int n_hist_exceeded;/*< Number of sessions that exceeded session - * command history limit */ - int sessions; - double ses_longest; /*< Longest session */ - double ses_shortest; /*< Shortest session */ - double ses_average; /*< Average session length */ - int shmap_cache_hit; /*< Shard map was found from the cache */ - int shmap_cache_miss;/*< No shard map found from the cache */ -} ROUTER_STATS; - -/** - * The client session structure used within this router. - */ -struct schemarouter_session -{ -#if defined(SS_DEBUG) - skygw_chk_t rses_chk_top; -#endif - bool closed; /*< true when closeSession is called */ - DCB* rses_client_dcb; - MYSQL_session* rses_mysql_session; /*< Session client data (username, password, SHA1). */ - backend_ref_t* rses_master_ref; /*< Router session master reference */ - backend_ref_t* rses_backend_ref; /*< Pointer to backend reference array */ - schemarouter_config_t rses_config; /*< Copied config info from router instance */ - int rses_nbackends; /*< Number of backends */ - bool rses_autocommit_enabled; /*< Is autocommit enabled */ - bool rses_transaction_active; /*< Is a transaction active */ - struct schemarouter_instance *router; /*< The router instance */ - struct schemarouter_session* next; /*< List of router sessions */ - Shard shardmap; /**< Database hash containing names of the databases - * mapped to the servers that contain them */ - char connect_db[MYSQL_DATABASE_MAXLEN + 1]; /*< Database the user was trying to connect to */ - char current_db[MYSQL_DATABASE_MAXLEN + 1]; /*< Current active database */ - int init; /*< Initialization state bitmask */ - GWBUF* queue; /*< Query that was received before the session was ready */ - DCB* dcb_route; /*< Internal DCB used to trigger re-routing of buffers */ - DCB* dcb_reply; /*< Internal DCB used to send replies to the client */ - ROUTER_STATS stats; /*< Statistics for this router */ - int n_sescmd; - int pos_generator; - - uint64_t sent_sescmd; /**< The latest session command being executed */ - uint64_t replied_sescmd; /**< The last session command reply that was sent to the client */ -#if defined(SS_DEBUG) - skygw_chk_t rses_chk_tail; -#endif -}; - - -/** - * The per instance data for the router. - */ -typedef struct schemarouter_instance -{ - ShardManager shard_manager; /*< Shard maps hashed by user name */ - SERVICE* service; /*< Pointer to service */ - SCHEMAROUTER_SESSION* connections; /*< List of client connections */ - SPINLOCK lock; /*< Lock for the instance data */ - schemarouter_config_t schemarouter_config; /*< expanded config info from SERVICE */ - int schemarouter_version;/*< version number for router's config */ - unsigned int bitmask; /*< Bitmask to apply to server->status */ - unsigned int bitvalue; /*< Required value of server->status */ - ROUTER_STATS stats; /*< Statistics for this router */ - struct schemarouter_instance* next; /*< Next router on the list */ - bool available_slaves; /*< The router has some slaves available */ - std::set ignored_dbs; /*< List of databases to ignore when the - * database mapping finds multiple servers - * with the same database */ - pcre2_code* ignore_regex; /*< Databases matching this regex will - * not cause the session to be terminated - * if they are found on more than one server. */ - pcre2_match_data* ignore_match_data; - -} SCHEMAROUTER; - -#define BACKEND_TYPE(b) (SERVER_IS_MASTER((b)->backend_server) ? BE_MASTER : \ - (SERVER_IS_SLAVE((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED)); - -MXS_END_DECLS - -#endif /*< _SCHEMAROUTER_H */ diff --git a/server/modules/routing/schemarouter/schemarouter.hh b/server/modules/routing/schemarouter/schemarouter.hh new file mode 100644 index 000000000..e5b608ae2 --- /dev/null +++ b/server/modules/routing/schemarouter/schemarouter.hh @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2019-07-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#pragma once + +/** + * @file schemarouter.hh - The schemarouter router module header file + */ + +#define MXS_MODULE_NAME "schemarouter" + +#include + +#include +#include + +#include +#include +#include +#include + +#include "shard_map.hh" +#include "session_command.hh" + +using std::string; +using std::set; + +/** + * Bitmask values for the router session's initialization. These values are used + * to prevent responses from internal commands being forwarded to the client. + */ +typedef enum init_mask +{ + INIT_READY = 0x00, + INIT_MAPPING = 0x01, + INIT_USE_DB = 0x02, + INIT_UNINT = 0x04, + INIT_FAILED = 0x08 +} init_mask_t; + +typedef enum showdb_response +{ + SHOWDB_FULL_RESPONSE, + SHOWDB_PARTIAL_RESPONSE, + SHOWDB_DUPLICATE_DATABASES, + SHOWDB_FATAL_ERROR +} showdb_response_t; + +/** + * The state of the backend server reference + */ +typedef enum bref_state +{ + BREF_IN_USE = 0x01, + BREF_WAITING_RESULT = 0x02, /**< for session commands only */ + BREF_QUERY_ACTIVE = 0x04, /**< for other queries */ + BREF_CLOSED = 0x08, + BREF_DB_MAPPED = 0x10 +} bref_state_t; + +#define BREF_IS_NOT_USED(s) ((s)->bref_state & ~BREF_IN_USE) +#define BREF_IS_IN_USE(s) ((s)->bref_state & BREF_IN_USE) +#define BREF_IS_WAITING_RESULT(s) ((s)->bref_num_result_wait > 0) +#define BREF_IS_QUERY_ACTIVE(s) ((s)->bref_state & BREF_QUERY_ACTIVE) +#define BREF_IS_CLOSED(s) ((s)->bref_state & BREF_CLOSED) +#define BREF_IS_MAPPED(s) ((s)->bref_mapped) + +#define SCHEMA_ERR_DUPLICATEDB 5000 +#define SCHEMA_ERRSTR_DUPLICATEDB "DUPDB" +#define SCHEMA_ERR_DBNOTFOUND 1049 +#define SCHEMA_ERRSTR_DBNOTFOUND "42000" + +struct schemarouter_instance; + +/** + * Route target types + */ +typedef enum +{ + TARGET_UNDEFINED = (1 << 0), + TARGET_NAMED_SERVER = (1 << 1), + TARGET_ALL = (1 << 2), + TARGET_ANY = (1 << 3) +} route_target_t; + +/** Helper macros for route target type */ +#define TARGET_IS_UNDEFINED(t) (t == TARGET_UNDEFINED) +#define TARGET_IS_NAMED_SERVER(t) (t & TARGET_NAMED_SERVER) +#define TARGET_IS_ALL(t) (t & TARGET_ALL) +#define TARGET_IS_ANY(t) (t & TARGET_ANY) + +/** + * Reference to BACKEND. + * + * Owned by router client session. + */ +typedef struct backend_ref_st +{ + int n_mapping_eof; + GWBUF* map_queue; + SERVER_REF* bref_backend; /*< Backend server */ + DCB* bref_dcb; /*< Backend DCB */ + int bref_state; /*< State of the backend */ + bool bref_mapped; /*< Whether the backend has been mapped */ + bool last_sescmd_replied; + int bref_num_result_wait; /*< Number of not yet received results */ + GWBUF* bref_pending_cmd; /*< Pending commands */ + + SessionCommandList session_commands; /**< List of session commands that are + * to be executed on this backend server */ +} backend_ref_t; + +/** + * Configuration values + */ +typedef struct schemarouter_config_st +{ + double refresh_min_interval; /**< Minimum required interval between refreshes of databases */ + bool refresh_databases; /**< Are databases refreshed when they are not found in the hashtable */ + bool debug; /**< Enable verbose debug messages to clients */ +} schemarouter_config_t; + +/** + * The statistics for this router instance + */ +typedef struct +{ + int n_queries; /*< Number of queries forwarded */ + int n_sescmd; /*< Number of session commands */ + int longest_sescmd; /*< Longest chain of stored session commands */ + int n_hist_exceeded; /*< Number of sessions that exceeded session + * command history limit */ + int sessions; + double ses_longest; /*< Longest session */ + double ses_shortest; /*< Shortest session */ + double ses_average; /*< Average session length */ + int shmap_cache_hit; /*< Shard map was found from the cache */ + int shmap_cache_miss; /*< No shard map found from the cache */ +} ROUTER_STATS; + +/** + * The per instance data for the router. + */ +typedef struct schemarouter_instance +{ + ShardManager shard_manager; /*< Shard maps hashed by user name */ + SERVICE* service; /*< Pointer to service */ + SPINLOCK lock; /*< Lock for the instance data */ + schemarouter_config_t schemarouter_config; /*< expanded config info from SERVICE */ + int schemarouter_version; /*< version number for router's config */ + ROUTER_STATS stats; /*< Statistics for this router */ + set ignored_dbs; /*< List of databases to ignore when the + * database mapping finds multiple servers + * with the same database */ + pcre2_code* ignore_regex; /*< Databases matching this regex will + * not cause the session to be terminated + * if they are found on more than one server. */ + pcre2_match_data* ignore_match_data; + +} SCHEMAROUTER; + +/** + * The client session structure used within this router. + */ +typedef struct schemarouter_session +{ + bool closed; /*< true when closeSession is called */ + DCB* rses_client_dcb; + MYSQL_session* rses_mysql_session; /*< Session client data (username, password, SHA1). */ + backend_ref_t* rses_backend_ref; /*< Pointer to backend reference array */ + schemarouter_config_t rses_config; /*< Copied config info from router instance */ + int rses_nbackends; /*< Number of backends */ + SCHEMAROUTER *router; /*< The router instance */ + Shard shardmap; /**< Database hash containing names of the databases + * mapped to the servers that contain them */ + string connect_db; /*< Database the user was trying to connect to */ + string current_db; /*< Current active database */ + int state; /*< Initialization state bitmask */ + GWBUF* queue; /*< Query that was received before the session was ready */ + ROUTER_STATS stats; /*< Statistics for this router */ + + uint64_t sent_sescmd; /**< The latest session command being executed */ + uint64_t replied_sescmd; /**< The last session command reply that was sent to the client */ +} SCHEMAROUTER_SESSION;