diff --git a/include/mysql_backend.h b/include/mysql_backend.h index af4a47c82..c02438863 100644 --- a/include/mysql_backend.h +++ b/include/mysql_backend.h @@ -275,6 +275,7 @@ class MySQL_HostGroups_Handler { // } }; */ + MySQL_Hostgroup * MyHostGroups_idx(unsigned int hid); void insert_hostgroup(MySQL_Hostgroup *myhg); /* void insert_hostgroup(MySQL_Hostgroup *myhg) { diff --git a/include/query_processor.h b/include/query_processor.h index d03231f04..a061be028 100644 --- a/include/query_processor.h +++ b/include/query_processor.h @@ -3,7 +3,6 @@ #include "proxysql.h" #include "cpp.h" - struct _Query_Processor_rule_t { int rule_id; bool active; @@ -18,6 +17,7 @@ struct _Query_Processor_rule_t { int cache_ttl; bool apply; void *regex_engine; + uint64_t hits; }; @@ -26,6 +26,7 @@ struct _Query_Processor_output_t { unsigned int size; int destination_hostgroup; int cache_ttl; + std::string *new_query; }; typedef struct _Query_Processor_rule_t QP_rule_t; diff --git a/lib/Standard_Query_Processor.cpp b/lib/Standard_Query_Processor.cpp index d24669ac0..dbe902cdf 100644 --- a/lib/Standard_Query_Processor.cpp +++ b/lib/Standard_Query_Processor.cpp @@ -130,6 +130,7 @@ virtual QP_rule_t * new_query_rule(int rule_id, bool active, char *username, cha newQR->cache_ttl=cache_ttl; newQR->apply=apply; newQR->regex_engine=NULL; + newQR->hits=0; proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Creating new rule in %p : rule_id:%d, active:%d, username=%s, schemaname=%s, flagIN:%d, %smatch_pattern=\"%s\", flagOUT:%d replace_pattern=\"%s\", destination_hostgroup:%d, apply:%d\n", newQR, newQR->rule_id, newQR->active, newQR->username, newQR->schemaname, newQR->flagIN, (newQR->negate_match_pattern ? "(!)" : "") , newQR->match_pattern, newQR->flagOUT, newQR->replace_pattern, newQR->destination_hostgroup, newQR->apply); return newQR; }; @@ -220,18 +221,88 @@ virtual QP_out_t * process_mysql_query(MySQL_Session *sess, void *ptr, unsigned } QP_rule_t *qr; re2_t *re2p; + int flagIN=0; for (std::vector::iterator it=_thr_SQP_rules->begin(); it!=_thr_SQP_rules->end(); ++it) { qr=*it; + if (qr->flagIN != flagIN) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 6, "query rule %d has no matching flagIN\n", qr->rule_id); + continue; + } + if (qr->username) { + if (strcmp(qr->username,sess->userinfo_client.username)!=0) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has no matching username\n", qr->rule_id); + continue; + } + } + if (qr->schemaname) { + if (strcmp(qr->schemaname,sess->userinfo_client.schemaname)!=0) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has no matching schemaname\n", qr->rule_id); + continue; + } + } + re2p=(re2_t *)qr->regex_engine; - if (qr->match_pattern && RE2::PartialMatch(query,*re2p->re)==true) { - //ret=(QP_out_t *)malloc(sizeof(QP_out_t)); + if (qr->match_pattern) { + bool rc; + if (ret && ret->new_query) { + // if we already rewrote the query, process the new query + //std::string *s=ret->new_query; + rc=RE2::PartialMatch(ret->new_query->c_str(),*re2p->re); + } else { + // we never rewrote the query + rc=RE2::PartialMatch(query,*re2p->re); + } + if ((rc==true && qr->negate_match_pattern==true) || ( rc==false && qr->negate_match_pattern==false )) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has no matching pattern\n", qr->rule_id); + continue; + } + } + // if we arrived here, we have a match + if (ret==NULL) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "this is the first time we find a match\n"); + // create struct ret=(QP_out_t *)l_alloc(sizeof(QP_out_t)); - ret->cache_ttl=qr->cache_ttl; + // initalized all values + ret->ptr=NULL; + ret->size=0; + ret->destination_hostgroup=-1; + ret->cache_ttl=-1; + ret->new_query=NULL; + } + //__sync_fetch_and _add(&qr->hits,1); + qr->hits++; // this is done without atomic function because it updates only the local variables + //ret=(QP_out_t *)malloc(sizeof(QP_out_t)); + + if (qr->flagOUT >= 0) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has changed flagOUT\n", qr->rule_id); + flagIN=qr->flagOUT; + //sess->query_info.flagOUT=flagIN; + } + if (qr->cache_ttl >= 0) { + // Note: negative TTL means this rule doesn't change + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has set cache_ttl: %d. Query will%s hit the cache\n", qr->rule_id, qr->cache_ttl, (qr->cache_ttl == 0 ? " NOT" : "" )); + ret->cache_ttl=qr->cache_ttl; + } + if (qr->destination_hostgroup >= 0) { + // Note: negative TTL means this rule doesn't change + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has set destination hostgroup: %d\n", qr->rule_id, qr->destination_hostgroup); + ret->destination_hostgroup=qr->destination_hostgroup; + } + + if (qr->replace_pattern) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d on match_pattern \"%s\" has a replace_pattern \"%s\" to apply\n", qr->rule_id, qr->match_pattern, qr->replace_pattern); + if (ret->new_query==NULL) ret->new_query=new std::string(query); + RE2::Replace(ret->new_query,qr->match_pattern,qr->replace_pattern); + } + + if (qr->apply==true) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d is the last one to apply: exit!\n", qr->rule_id); goto __exit_process_mysql_query; } } __exit_process_mysql_query: + // FIXME : there is too much data being copied around l_free(len+1,query); return ret; }; diff --git a/lib/mysql_backend.cpp b/lib/mysql_backend.cpp index 9199e8582..ce0de4158 100644 --- a/lib/mysql_backend.cpp +++ b/lib/mysql_backend.cpp @@ -67,12 +67,21 @@ MySQL_Hostgroup_Entry * MySQL_HostGroups_Handler::set_HG_entry_status(unsigned i //MySQL_Hostgroup_Entry * MySQL_HostGroups_Handler::server_add_hg(unsigned int hid, char *add=NULL, uint16_t p=3306, unsigned int _weight=1) { MySQL_Hostgroup_Entry * MySQL_HostGroups_Handler::server_add_hg(unsigned int hid, char *add, uint16_t p, unsigned int _weight) { proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Adding MySQL server %s:%d in Global Handler in hostgroup\n", add, p, hid); + MySQL_Server *srv=server_add(add,p); + MySQL_Hostgroup *myhg=MyHostGroups_idx(hid); + return myhg->server_add(srv, _weight); +} + +MySQL_Hostgroup * MySQL_HostGroups_Handler::MyHostGroups_idx(unsigned int hid) { if (hid>=MyHostGroups->len) { create_hostgroup(hid); - }; - MySQL_Server *srv=server_add(add,p); + } MySQL_Hostgroup *myhg=(MySQL_Hostgroup *)MyHostGroups->index(hid); - return myhg->server_add(srv, _weight); + if (myhg==NULL) { + create_hostgroup(hid); + myhg=(MySQL_Hostgroup *)MyHostGroups->index(hid); + } + return myhg; } MySQL_Hostgroup_Entry * MySQL_HostGroups_Handler::MSHGE_find(unsigned int hid, MySQL_Server *srv) { diff --git a/lib/mysql_session.cpp b/lib/mysql_session.cpp index 2a31d906a..10b4e3936 100644 --- a/lib/mysql_session.cpp +++ b/lib/mysql_session.cpp @@ -313,6 +313,7 @@ int MySQL_Session::handler() { case WAITING_CLIENT_DATA: switch (client_myds->DSS) { case STATE_SLEEP: + current_hostgroup=default_hostgroup; proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Statuses: WAITING_CLIENT_DATA - STATE_SLEEP\n"); //unsigned char c; c=*((unsigned char *)pkt.ptr+sizeof(mysql_hdr));