Skip to content

Commit

Permalink
Merge pull request #3001 from sysown/v2.0.14-vars
Browse files Browse the repository at this point in the history
Implemented fix for issue #3000
  • Loading branch information
renecannao authored Sep 3, 2020
2 parents af3d121 + 04bda26 commit bdb56df
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 133 deletions.
12 changes: 7 additions & 5 deletions include/MySQL_HostGroups_Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@

#include "ev.h"

/*
Enabling STRESSTEST_POOL ProxySQL will do a lot of loops in the connection pool
This is for internal testing ONLY!!!!
#define STRESSTEST_POOL
*/
#ifdef DEBUG
/* */
// Enabling STRESSTEST_POOL ProxySQL will do a lot of loops in the connection pool
// This is for internal testing ONLY!!!!
//#define STRESSTEST_POOL
#endif // DEBUG

#define MHM_PTHREAD_MUTEX

Expand Down Expand Up @@ -116,6 +117,7 @@ class MySrvConnList {
}
MySQL_Connection *remove(int);
MySQL_Connection * get_random_MyConn(MySQL_Session *sess, bool ff);
void get_random_MyConn_inner_search(unsigned int start, unsigned int end, unsigned int& conn_found_idx, unsigned int& connection_quality_level, unsigned int& number_of_matching_session_variables, const MySQL_Connection * client_conn);
unsigned int conns_length() { return conns->len; }
void drop_all_connections();
MySQL_Connection *index(unsigned int);
Expand Down
4 changes: 3 additions & 1 deletion include/mysql_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,9 @@ class MySQL_Connection {
bool get_gtid(char *buff, uint64_t *trx_id);
void reduce_auto_increment_delay_token() { if (auto_increment_delay_token) auto_increment_delay_token--; };

bool match_tracked_options(MySQL_Connection *c);
bool match_tracked_options(const MySQL_Connection *c);
bool requires_CHANGE_USER(const MySQL_Connection *client_conn);
unsigned int number_of_matching_session_variables(const MySQL_Connection *client_conn, unsigned int& not_matching);
unsigned long get_mysql_thread_id() { return mysql ? mysql->thread_id : 0; }
};
#endif /* __CLASS_MYSQL_CONNECTION_H */
131 changes: 85 additions & 46 deletions lib/MySQL_HostGroups_Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2602,11 +2602,66 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_

//MySrvC * MySrvList::idx(unsigned int i) { return (MySrvC *)servers->index(i); }


void MySrvConnList::get_random_MyConn_inner_search(unsigned int start, unsigned int end, unsigned int& conn_found_idx, unsigned int& connection_quality_level, unsigned int& number_of_matching_session_variables, const MySQL_Connection * client_conn) {
char *schema = client_conn->userinfo->schemaname;
MySQL_Connection * conn=NULL;
unsigned int k;
for (k = start; k < end; k++) {
conn = (MySQL_Connection *)conns->index(k);
if (conn->match_tracked_options(client_conn)) {
if (connection_quality_level == 0) {
// this is our best candidate so far
connection_quality_level = 1;
conn_found_idx = k;
}
if (conn->requires_CHANGE_USER(client_conn)==false) {
if (connection_quality_level == 1) {
// this is our best candidate so far
connection_quality_level = 2;
conn_found_idx = k;
}
unsigned int cnt_match = 0; // number of matching session variables
unsigned int not_match = 0; // number of not matching session variables
cnt_match = conn->number_of_matching_session_variables(client_conn, not_match);
if (strcmp(conn->userinfo->schemaname,schema)==0) {
cnt_match++;
} else {
not_match++;
}
if (not_match==0) {
// it seems we found the perfect connection
number_of_matching_session_variables = cnt_match;
connection_quality_level = 3;
conn_found_idx = k;
return; // exit immediately, we found the perfect connection
} else {
// we didn't find the perfect connection
// but maybe is better than what we have so far?
if (cnt_match > number_of_matching_session_variables) {
// this is our best candidate so far
number_of_matching_session_variables = cnt_match;
conn_found_idx = k;
}
}
}
}
}
}

MySQL_Connection * MySrvConnList::get_random_MyConn(MySQL_Session *sess, bool ff) {
MySQL_Connection * conn=NULL;
unsigned int i;
unsigned int conn_found_idx;
unsigned int l=conns_length();
unsigned int connection_quality_level = 0;
bool needs_warming = false;
// connection_quality_level:
// 0 : not found any good connection, tracked options are not OK
// 1 : tracked options are OK , but CHANGE USER is required
// 2 : tracked options are OK , CHANGE USER is not required, but some SET statement or INIT_DB needs to be executed
// 3 : tracked options are OK , CHANGE USER is not required, and it seems that SET statements or INIT_DB ARE not required
unsigned int number_of_matching_session_variables = 0; // this includes session variables AND schema
if (mysql_thread___connection_warming) {
unsigned int total_connections = mysrvc->ConnectionsFree->conns_length()+mysrvc->ConnectionsUsed->conns_length();
unsigned int expected_warm_connections = mysql_thread___free_connections_pct*mysrvc->max_connections/100;
Expand All @@ -2621,61 +2676,45 @@ MySQL_Connection * MySrvConnList::get_random_MyConn(MySQL_Session *sess, bool ff
i=fastrand()%l;
}
if (sess && sess->client_myds && sess->client_myds->myconn && sess->client_myds->myconn->userinfo) {
// try to match schemaname AND username
char *schema = sess->client_myds->myconn->userinfo->schemaname;
char *username = sess->client_myds->myconn->userinfo->username;
MySQL_Connection * client_conn = sess->client_myds->myconn;
bool conn_found = false;
unsigned int k;
bool options_matching_found = false;
for (k = i; conn_found == false && k < l; k++) {
conn = (MySQL_Connection *)conns->index(k);
if (conn->match_tracked_options(client_conn)) {
if (options_matching_found == false) {
options_matching_found = true;
}
if (strcmp(conn->userinfo->schemaname,schema)==0 && strcmp(conn->userinfo->username,username)==0) {
conn_found = true;
i = k;
}
}
get_random_MyConn_inner_search(i, l, conn_found_idx, connection_quality_level, number_of_matching_session_variables, client_conn);
if (connection_quality_level !=3 ) { // we didn't find the perfect connection
get_random_MyConn_inner_search(0, i, conn_found_idx, connection_quality_level, number_of_matching_session_variables, client_conn);
}
if (conn_found == false ) {
for (k = 0; conn_found == false && k < i; k++) {
conn = (MySQL_Connection *)conns->index(k);
if (conn->match_tracked_options(client_conn)) {
if (options_matching_found == false) {
options_matching_found = true;
}
if (strcmp(conn->userinfo->schemaname,schema)==0 && strcmp(conn->userinfo->username,username)==0) {
conn_found = true;
i = k;
}
}
}
}
if (conn_found == true) {
conn=(MySQL_Connection *)conns->remove_index_fast(i);
} else {
if (options_matching_found == false) {
// connection_quality_level:
// 1 : tracked options are OK , but CHANGE USER is required
// 2 : tracked options are OK , CHANGE USER is not required, but some SET statement or INIT_DB needs to be executed
switch (connection_quality_level) {
case 0: // not found any good connection, tracked options are not OK
// we must create a new connection
conn = new MySQL_Connection();
conn->parent=mysrvc;
__sync_fetch_and_add(&MyHGM->status.server_connections_created, 1);
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySQL Connection %p, server %s:%d\n", conn, conn->parent->address, conn->parent->port);
} else {
break;
case 1: //tracked options are OK , but CHANGE USER is required
// we may consider creating a new connection
unsigned int conns_free = mysrvc->ConnectionsFree->conns_length();
unsigned int conns_used = mysrvc->ConnectionsUsed->conns_length();
if ((conns_used > conns_free) && (mysrvc->max_connections > (conns_free/2 + conns_used/2)) ) {
conn = new MySQL_Connection();
conn->parent=mysrvc;
__sync_fetch_and_add(&MyHGM->status.server_connections_created, 1);
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySQL Connection %p, server %s:%d\n", conn, conn->parent->address, conn->parent->port);
} else {
conn=(MySQL_Connection *)conns->remove_index_fast(i);
{
unsigned int conns_free = mysrvc->ConnectionsFree->conns_length();
unsigned int conns_used = mysrvc->ConnectionsUsed->conns_length();
if ((conns_used > conns_free) && (mysrvc->max_connections > (conns_free/2 + conns_used/2)) ) {
conn = new MySQL_Connection();
conn->parent=mysrvc;
__sync_fetch_and_add(&MyHGM->status.server_connections_created, 1);
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySQL Connection %p, server %s:%d\n", conn, conn->parent->address, conn->parent->port);
} else {
conn=(MySQL_Connection *)conns->remove_index_fast(conn_found_idx);
}
}
}
break;
case 2: // tracked options are OK , CHANGE USER is not required, but some SET statement or INIT_DB needs to be executed
case 3: // tracked options are OK , CHANGE USER is not required, and it seems that SET statements or INIT_DB ARE not required
// here we return the best connection we have, no matter if connection_quality_level is 2 or 3
conn=(MySQL_Connection *)conns->remove_index_fast(conn_found_idx);
break;
default: // this should never happen
assert(0);
break;
}
} else {
conn=(MySQL_Connection *)conns->remove_index_fast(i);
Expand Down
57 changes: 57 additions & 0 deletions lib/MySQL_Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1879,6 +1879,25 @@ bool MySQL_Session::handler_again___verify_backend_user_schema() {
NEXT_IMMEDIATE_NEW(CHANGING_SCHEMA);
}
}
// if we reach here, the username is the same
if (myds->myconn->requires_CHANGE_USER(client_myds->myconn)) {
// if we reach here, even if the username is the same,
// the backend connection has some session variable set
// that the client never asked for
// because we can't unset variables, we will reset the connection
switch(status) {
case PROCESSING_QUERY:
case PROCESSING_STMT_PREPARE:
case PROCESSING_STMT_EXECUTE:
previous_status.push(status);
break;
default:
assert(0);
break;
}
mybe->server_myds->wait_until = thread->curtime + mysql_thread___connect_timeout_server*1000; // max_timeout
NEXT_IMMEDIATE_NEW(CHANGING_USER_SERVER);
}
return false;
}

Expand Down Expand Up @@ -5842,20 +5861,58 @@ void MySQL_Session::handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED
}
}
uuid[n]='\0';

#ifdef STRESSTEST_POOL
mc=thread->get_MyConn_local(mybe->hostgroup_id, this, uuid, trxid, -1);
#endif // STRESSTEST_POOL
} else {
#ifdef STRESSTEST_POOL
mc=thread->get_MyConn_local(mybe->hostgroup_id, this, NULL, 0, (int)qpo->max_lag_ms);
#endif // STRESSTEST_POOL
}
}
#ifdef STRESSTEST_POOL
// Check STRESSTEST_POOL in MySQL_HostGroups_Manager.h
// Note: this works only if session_fast_forward==false and create_new_conn is false too
#define NUM_SLOW_LOOPS 1000
// if STRESSTESTPOOL_MEASURE is define, time is measured in Query_Processor_time_nsec
// even if not the right variable
//#define STRESSTESTPOOL_MEASURE
#ifdef STRESSTESTPOOL_MEASURE
timespec begint;
timespec endt;
clock_gettime(CLOCK_MONOTONIC,&begint);
#endif // STRESSTESTPOOL_MEASURE
for (unsigned int loops=0; loops < NUM_SLOW_LOOPS; loops++) {
#endif // STRESSTEST_POOL
if (mc==NULL) {
if (trxid) {
mc=MyHGM->get_MyConn_from_pool(mybe->hostgroup_id, this, (session_fast_forward || qpo->create_new_conn), uuid, trxid, -1);
} else {
mc=MyHGM->get_MyConn_from_pool(mybe->hostgroup_id, this, (session_fast_forward || qpo->create_new_conn), NULL, 0, (int)qpo->max_lag_ms);
}
#ifdef STRESSTEST_POOL
if (mc && (loops < NUM_SLOW_LOOPS - 1)) {
if (mc->mysql) {
mybe->server_myds->attach_connection(mc);
mybe->server_myds->DSS=STATE_NOT_INITIALIZED;
mybe->server_myds->return_MySQL_Connection_To_Pool();
mc=NULL;
}
}
#endif // STRESSTEST_POOL
} else {
thread->status_variables.ConnPool_get_conn_immediate++;
}
#ifdef STRESSTEST_POOL
#ifdef STRESSTESTPOOL_MEASURE
clock_gettime(CLOCK_MONOTONIC,&endt);
thread->status_variables.query_processor_time=thread->status_variables.query_processor_time +
(endt.tv_sec*1000000000+endt.tv_nsec) -
(begint.tv_sec*1000000000+begint.tv_nsec);
#endif // STRESSTESTPOOL_MEASURE
}
#endif // STRESSTEST_POOL
if (mc) {
mybe->server_myds->attach_connection(mc);
thread->status_variables.ConnPool_get_conn_success++;
Expand Down
Loading

0 comments on commit bdb56df

Please sign in to comment.