diff --git a/server/modules/routing/readwritesplit/readwritesplit.cc b/server/modules/routing/readwritesplit/readwritesplit.cc index afbb8b745..d22307711 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.cc +++ b/server/modules/routing/readwritesplit/readwritesplit.cc @@ -306,18 +306,23 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *router_inst, MXS_SESSION *sess { ROUTER_INSTANCE* router = (ROUTER_INSTANCE*)router_inst; ROUTER_CLIENT_SES* client_rses = new (std::nothrow) ROUTER_CLIENT_SES; + rses_property_t* prop = rses_property_init(RSES_PROP_TYPE_TMPTABLES); - if (client_rses == NULL) + if (client_rses == NULL || prop == NULL) { + delete client_rses; + delete prop; return NULL; } + + prop->rses_prop_rsession = client_rses; #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->rses_properties[RSES_PROP_TYPE_SESCMD] = NULL; - client_rses->rses_properties[RSES_PROP_TYPE_TMPTABLES] = NULL; + client_rses->rses_properties[RSES_PROP_TYPE_TMPTABLES] = prop; client_rses->rses_closed = false; client_rses->router = router; client_rses->client_dcb = session->client_dcb; @@ -1069,10 +1074,13 @@ rses_property_t *rses_property_init(rses_property_type_t prop_type) if (prop == NULL) { + MXS_OOM(); return NULL; } prop->rses_prop_type = prop_type; + prop->rses_prop_next = NULL; + prop->rses_prop_refcount = 1; #if defined(SS_DEBUG) prop->rses_prop_chk_top = CHK_NUM_ROUTER_PROPERTY; prop->rses_prop_chk_tail = CHK_NUM_ROUTER_PROPERTY; @@ -1101,7 +1109,7 @@ void rses_property_done(rses_property_t *prop) break; case RSES_PROP_TYPE_TMPTABLES: - hashtable_free(prop->rses_prop_data.temp_tables); + // Nothing to do break; default: @@ -1111,6 +1119,7 @@ void rses_property_done(rses_property_t *prop) ss_dassert(false); break; } + delete prop; } diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index eecb801c0..d0356e399 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -20,6 +20,9 @@ #include +#include +#include + #include #include #include @@ -153,6 +156,8 @@ struct mysql_sescmd_t skygw_chk_t my_sescmd_chk_tail; }; +typedef std::tr1::unordered_set TableSet; + /** * Property structure */ @@ -163,10 +168,10 @@ struct rses_property_t int rses_prop_refcount; rses_property_type_t rses_prop_type; - union rses_prop_data + struct rses_prop_data // TODO: Remove the properties and integrate them into the session object { mysql_sescmd_t sescmd; - HASHTABLE* temp_tables; + TableSet temp_tables; } rses_prop_data; rses_property_t* rses_prop_next; /**< next property of same type */ skygw_chk_t rses_prop_chk_tail; diff --git a/server/modules/routing/readwritesplit/rwsplit_internal.hh b/server/modules/routing/readwritesplit/rwsplit_internal.hh index ffd532f0c..89ddd60a1 100644 --- a/server/modules/routing/readwritesplit/rwsplit_internal.hh +++ b/server/modules/routing/readwritesplit/rwsplit_internal.hh @@ -125,9 +125,7 @@ bool select_connect_backend_servers(backend_ref_t **p_master_ref, /* * The following are implemented in rwsplit_tmp_table_multi.c */ -void check_drop_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, - GWBUF *querybuf, - uint32_t packet_type); +void check_drop_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf); bool is_read_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf, uint32_t type); diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 961307e92..74c1e2209 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -990,7 +990,7 @@ handle_multi_temp_and_load(ROUTER_CLIENT_SES *rses, GWBUF *querybuf, */ if (rses->have_tmp_tables) { - check_drop_tmp_table(rses, querybuf, packet_type); + check_drop_tmp_table(rses, querybuf); if (is_packet_a_query(packet_type) && is_read_tmp_table(rses, querybuf, *qtype)) { *qtype |= QUERY_TYPE_MASTER_READ; diff --git a/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc b/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc index 925217b8a..ca00bb765 100644 --- a/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc +++ b/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc @@ -44,52 +44,27 @@ * @param querybuf GWBUF containing the query * @param type The type of the query resolved so far */ -void check_drop_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf, - uint32_t packet_type) +void check_drop_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf) { - if (packet_type != MYSQL_COM_QUERY && packet_type != MYSQL_COM_DROP_DB) - { - return; - } - - int tsize = 0, klen = 0, i; - char **tbl = NULL; - char *hkey, *dbname; - MYSQL_session *my_data; - rses_property_t *rses_prop_tmp; - MYSQL_session *data = (MYSQL_session *)router_cli_ses->client_dcb->data; - - rses_prop_tmp = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; - dbname = (char *)data->db; - if (qc_is_drop_table_query(querybuf)) { - tbl = qc_get_table_names(querybuf, &tsize, false); - if (tbl != NULL) - { - for (i = 0; i < tsize; i++) - { - /* Not clear why the next six lines are outside the if block */ - klen = strlen(dbname) + strlen(tbl[i]) + 2; - hkey = (char*)MXS_CALLOC(klen, sizeof(char)); - MXS_ABORT_IF_NULL(hkey); - strcpy(hkey, dbname); - strcat(hkey, "."); - strcat(hkey, tbl[i]); + const QC_FIELD_INFO* info; + size_t n_infos; + qc_get_field_info(querybuf, &info, &n_infos); - if (rses_prop_tmp && rses_prop_tmp->rses_prop_data.temp_tables) - { - if (hashtable_delete(rses_prop_tmp->rses_prop_data.temp_tables, - (void *)hkey)) - { - MXS_INFO("Temporary table dropped: %s", hkey); - } - } - MXS_FREE(tbl[i]); - MXS_FREE(hkey); + for (size_t i = 0; i < n_infos; i++) + { + MYSQL_session* data = static_cast(router_cli_ses->client_dcb->data); + std::string table = info[i].database ? info[i].database : data->db; + table += "."; + + if (info[i].table) + { + table += info[i].table; } - MXS_FREE(tbl); + rses_property_t* prop = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; + prop->rses_prop_data.temp_tables.erase(table); } } } @@ -105,77 +80,42 @@ bool is_read_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf, uint32_t qtype) { - - bool target_tmp_table = false; - int tsize = 0, klen = 0, i; - char **tbl = NULL; - char *dbname; - char hkey[MYSQL_DATABASE_MAXLEN + MYSQL_TABLE_MAXLEN + 2]; - MYSQL_session *data; + ss_dassert(router_cli_ses && querybuf && router_cli_ses->client_dcb); bool rval = false; - rses_property_t *rses_prop_tmp; - if (router_cli_ses == NULL || querybuf == NULL) + if (qtype & (QUERY_TYPE_READ | + QUERY_TYPE_LOCAL_READ | + QUERY_TYPE_USERVAR_READ | + QUERY_TYPE_SYSVAR_READ | + QUERY_TYPE_GSYSVAR_READ)) { - MXS_ERROR("[%s] Error: NULL parameters passed: %p %p", __FUNCTION__, - router_cli_ses, querybuf); - return false; - } + const QC_FIELD_INFO* info; + size_t n_infos; + qc_get_field_info(querybuf, &info, &n_infos); - if (router_cli_ses->client_dcb == NULL) - { - MXS_ERROR("[%s] Error: Client DCB is NULL.", __FUNCTION__); - return false; - } - - rses_prop_tmp = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; - data = (MYSQL_session *)router_cli_ses->client_dcb->data; - - if (data == NULL) - { - MXS_ERROR("[%s] Error: User data in client DBC is NULL.", __FUNCTION__); - return false; - } - - dbname = (char *)data->db; - - if (qc_query_is_type(qtype, QUERY_TYPE_READ) || - qc_query_is_type(qtype, QUERY_TYPE_LOCAL_READ) || - qc_query_is_type(qtype, QUERY_TYPE_USERVAR_READ) || - qc_query_is_type(qtype, QUERY_TYPE_SYSVAR_READ) || - qc_query_is_type(qtype, QUERY_TYPE_GSYSVAR_READ)) - { - tbl = qc_get_table_names(querybuf, &tsize, false); - - if (tbl != NULL && tsize > 0) + for (size_t i = 0; i < n_infos; i++) { - /** Query targets at least one table */ - for (i = 0; i < tsize && !target_tmp_table && tbl[i]; i++) + MYSQL_session* data = static_cast(router_cli_ses->client_dcb->data); + std::string table = info[i].database ? info[i].database : data->db; + table += "."; + + if (info[i].table) { - sprintf(hkey, "%s.%s", dbname, tbl[i]); - if (rses_prop_tmp && rses_prop_tmp->rses_prop_data.temp_tables) - { - if (hashtable_fetch(rses_prop_tmp->rses_prop_data.temp_tables, hkey)) - { - /**Query target is a temporary table*/ - rval = true; - MXS_INFO("Query targets a temporary table: %s", hkey); - break; - } - } + table += info[i].table; + } + + rses_property_t* prop = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; + + if (prop->rses_prop_data.temp_tables.find(table) != + prop->rses_prop_data.temp_tables.end()) + { + rval = true; + MXS_INFO("Query targets a temporary table: %s", table.c_str()); + break; } } } - if (tbl != NULL) - { - for (i = 0; i < tsize; i++) - { - MXS_FREE(tbl[i]); - } - MXS_FREE(tbl); - } - return rval; } @@ -191,112 +131,29 @@ bool is_read_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, void check_create_tmp_table(ROUTER_CLIENT_SES *router_cli_ses, GWBUF *querybuf, uint32_t type) { - if (!qc_query_is_type(type, QUERY_TYPE_CREATE_TMP_TABLE)) + if (qc_query_is_type(type, QUERY_TYPE_CREATE_TMP_TABLE)) { - return; - } + ss_dassert(router_cli_ses && querybuf && router_cli_ses->client_dcb && + router_cli_ses->client_dcb->data); - int klen = 0; - char *hkey, *dbname; - MYSQL_session *data; - rses_property_t *rses_prop_tmp; - HASHTABLE *h; + router_cli_ses->have_tmp_tables = true; + char* tblname = qc_get_created_table_name(querybuf); + std::string table; - if (router_cli_ses == NULL || querybuf == NULL) - { - MXS_ERROR("[%s] Error: NULL parameters passed: %p %p", __FUNCTION__, - router_cli_ses, querybuf); - return; - } - - if (router_cli_ses->client_dcb == NULL) - { - MXS_ERROR("[%s] Error: Client DCB is NULL.", __FUNCTION__); - return; - } - - router_cli_ses->have_tmp_tables = true; - rses_prop_tmp = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; - data = (MYSQL_session *)router_cli_ses->client_dcb->data; - - if (data == NULL) - { - MXS_ERROR("[%s] Error: User data in master server DBC is NULL.", - __FUNCTION__); - return; - } - - dbname = (char *)data->db; - - bool is_temp = true; - char *tblname = NULL; - - tblname = qc_get_created_table_name(querybuf); - - if (tblname && strlen(tblname) > 0) - { - klen = strlen(dbname) + strlen(tblname) + 2; - hkey = (char*)MXS_CALLOC(klen, sizeof(char)); - MXS_ABORT_IF_NULL(hkey); - strcpy(hkey, dbname); - strcat(hkey, "."); - strcat(hkey, tblname); - } - else - { - hkey = NULL; - } - - if (rses_prop_tmp == NULL) - { - if ((rses_prop_tmp = (rses_property_t *)MXS_CALLOC(1, sizeof(rses_property_t)))) + if (tblname && *tblname) { -#if defined(SS_DEBUG) - rses_prop_tmp->rses_prop_chk_top = CHK_NUM_ROUTER_PROPERTY; - rses_prop_tmp->rses_prop_chk_tail = CHK_NUM_ROUTER_PROPERTY; -#endif - rses_prop_tmp->rses_prop_rsession = router_cli_ses; - rses_prop_tmp->rses_prop_refcount = 1; - rses_prop_tmp->rses_prop_next = NULL; - rses_prop_tmp->rses_prop_type = RSES_PROP_TYPE_TMPTABLES; - router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES] = rses_prop_tmp; - } - } - if (rses_prop_tmp) - { - if (rses_prop_tmp->rses_prop_data.temp_tables == NULL) - { - h = hashtable_alloc(7, rwsplit_hashkeyfun, rwsplit_hashcmpfun); - hashtable_memory_fns(h, rwsplit_hstrdup, NULL, rwsplit_hfree, NULL); - if (h != NULL) - { - rses_prop_tmp->rses_prop_data.temp_tables = h; - } - else - { - MXS_ERROR("Failed to allocate a new hashtable."); - } + MYSQL_session* data = static_cast(router_cli_ses->client_dcb->data); + table += data->db; + table += "."; + table += tblname; } - if (hkey && rses_prop_tmp->rses_prop_data.temp_tables && - hashtable_add(rses_prop_tmp->rses_prop_data.temp_tables, (void *)hkey, - (void *)is_temp) == 0) /*< Conflict in hash table */ - { - MXS_INFO("Temporary table conflict in hashtable: %s", hkey); - } -#if defined(SS_DEBUG) - { - bool retkey = hashtable_fetch(rses_prop_tmp->rses_prop_data.temp_tables, hkey); - if (retkey) - { - MXS_INFO("Temporary table added: %s", hkey); - } - } -#endif - } + /** Add the table to the set of temporary tables */ + rses_property_t* prop = router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES]; + prop->rses_prop_data.temp_tables.insert(table); - MXS_FREE(hkey); - MXS_FREE(tblname); + MXS_FREE(tblname); + } } /**