Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for 'COM_RESET_CONNECTION' and 'COM_CHANGE_USER' fixes - Closes #2021 #3645

Merged
merged 8 commits into from
Nov 19, 2021
Merged
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ deps/libssl/openssl-1.1.1b/
deps/libssl/openssl-1.1.1d/
deps/libssl/openssl-1.1.1g/
deps/libssl/openssl-1.1.1j/
deps/libssl/openssl-openssl-3.0.0/

#google coredumper
deps/google-coredumper/google-coredumper/
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Useful links
===============

- [Official website](https://www.proxysql.com/)
- [Subscriptions and Support](https://proxysql.com/services/support/)
- [Documentation](https://www.proxysql.com/Documentation)
- [DockerHub Repository](https://hub.docker.com/r/proxysql/proxysql)
- [Benchmarks and blog posts](http://www.proxysql.blogspot.com/)
Expand Down
6 changes: 2 additions & 4 deletions deps/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ libssl/openssl/libssl.a:
cd libssl && rm -rf openssl-1.1.0h || true
cd libssl && rm -rf openssl-1.1.1g || true
cd libssl && rm -rf openssl-1.1.1j || true
cd libssl && rm -rf openssl-openssl-3.0.0 || true
cd libssl && tar -zxf openssl-3.0.0.tar.gz
cd libssl/openssl && ./config no-ssl3 no-tests
cd libssl && tar -zxf openssl-1.1.1j.tar.gz
cd libssl/openssl && ./config no-ssl3
cd libssl/openssl && CC=${CC} CXX=${CXX} ${MAKE}
cd libssl/openssl && ln -s . lib # curl wants this path
libssl: libssl/openssl/libssl.a
Expand Down Expand Up @@ -289,7 +288,6 @@ cleanall:
cd libssl && rm -rf openssl-1.1.1d || true
cd libssl && rm -rf openssl-1.1.1g || true
cd libssl && rm -rf openssl-1.1.1j || true
cd libssl && rm -rf openssl-openssl-3.0.0 || true
cd libconfig && rm -rf libconfig-1.7.2 || true
cd prometheus-cpp && rm -rf prometheus-cpp-0.9.0 || true
.PHONY: cleanall
Expand Down
2 changes: 1 addition & 1 deletion deps/libssl/openssl
Binary file removed deps/libssl/openssl-3.0.0.tar.gz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ set -eu
echo "==> Build environment:"
env

echo "==> Dirty patching to ensure OS deps are installed"

yum -y install gnutls-devel libtool || true
yum -y install epel-release
sed -i "s/mirrorlist=https/mirrorlist=http/" /etc/yum.repos.d/epel.repo
yum -y install http://repo.okay.com.mx/centos/6/x86_64/release/okay-release-1-1.noarch.rpm
yum -y upgrade automake autoconf

echo "==> Cleaning"
# Delete package if exists
rm -f /opt/proxysql/binaries/proxysql-${CURVER}-1-${PKG_RELEASE}.x86_64.rpm || true
Expand Down
6 changes: 2 additions & 4 deletions include/MySQL_HostGroups_Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class GTID_Server_Data {

class MySrvConnList {
private:
PtrArray *conns;
MySrvC *mysrvc;
int find_idx(MySQL_Connection *c) {
//for (unsigned int i=0; i<conns_length(); i++) {
Expand All @@ -108,7 +109,6 @@ class MySrvConnList {
return -1;
}
public:
PtrArray *conns;
MySrvConnList(MySrvC *);
~MySrvConnList();
void add(MySQL_Connection *);
Expand Down Expand Up @@ -160,7 +160,7 @@ class MySrvC { // MySQL Server Container
MySrvConnList *ConnectionsFree;
MySrvC(char *, uint16_t, uint16_t, unsigned int, enum MySerStatus, unsigned int, unsigned int _max_connections, unsigned int _max_replication_lag, unsigned int _use_ssl, unsigned int _max_latency_ms, char *_comment);
~MySrvC();
void connect_error(int, bool get_mutex=true);
void connect_error(int);
void shun_and_killall();
/**
* Update the maximum number of used connections
Expand Down Expand Up @@ -609,8 +609,6 @@ class MySQL_HostGroups_Manager {
SQLite3_result *get_mysql_errors(bool);

void shutdown();
void unshun_server_all_hostgroups(const char * address, uint16_t port, time_t t, int max_wait_sec, unsigned int *skip_hid);
MySrvC* find_server_in_hg(unsigned int _hid, const std::string& addr, int port);
};

#endif /* __CLASS_MYSQL_HOSTGROUPS_MANAGER_H */
41 changes: 23 additions & 18 deletions include/MySQL_Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ enum proxysql_session_type {
PROXYSQL_SESSION_NONE
};

std::string proxysql_session_type_str(enum proxysql_session_type session_type);

// these structs will be used for various regex hardcoded
// their initial use will be for sql_log_bin , sql_mode and time_zone
// issues #509 , #815 and #816
Expand Down Expand Up @@ -94,7 +96,21 @@ class MySQL_Session
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PING(PtrSize_t *);

void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_CHANGE_USER(PtrSize_t *, bool *);

/**
* @brief Handles the command 'COM_RESET_CONNECTION'.
* @param pkt Pointer to packet received holding the 'COM_RESET_CONNECTION'.
* @details 'COM_RESET_CONNECTION' command is currently supported only for 'sesssion_types':
* - 'PROXYSQL_SESSION_MYSQL'.
* - 'PROXYSQL_SESSION_SQLITE'.
* If the command is received for other sessions, the an error packet with error '1047' is sent to the
* client. If the session is supported, it performs the following operations over the current session:
* 1. Store the current relevent session variables to be recovered after the 'RESET'.
* 2. Perform a reset and initialization of current session.
* 3. Recover the relevant session variables and other initial state associated with the current session
* user.
* 4. Respond to client with 'OK' packet.
*/
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_RESET_CONNECTION(PtrSize_t *pkt);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_SET_OPTION(PtrSize_t *);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_STATISTICS(PtrSize_t *);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PROCESS_KILL(PtrSize_t *);
Expand All @@ -106,11 +122,6 @@ class MySQL_Session
bool handler_special_queries(PtrSize_t *);
bool handler_CommitRollback(PtrSize_t *);
bool handler_SetAutocommit(PtrSize_t *);
/**
* @brief Performs the cleanup of current session state, and the required operations to the supplied
* 'MySQL_Data_Stream' required for processing further queries.
* @param The 'MySQL_Data_Stream' which executed the previous query and which status should be updated.
*/
void RequestEnd(MySQL_Data_Stream *);
void LogQuery(MySQL_Data_Stream *);

Expand Down Expand Up @@ -214,6 +225,12 @@ class MySQL_Session
int user_max_connections;
int current_hostgroup;
int default_hostgroup;
/**
* @brief Charset directly specified by the client. Supplied and updated via 'HandshakeResponse'
* and 'COM_CHANGE_USER' packets.
* @details Used when session needs to be restored via 'COM_RESET_CONNECTION'.
*/
int default_charset;
int locked_on_hostgroup;
int next_query_flagIN;
int mirror_hostgroup;
Expand Down Expand Up @@ -286,18 +303,6 @@ class MySQL_Session
void Memory_Stats();
void create_new_session_and_reset_connection(MySQL_Data_Stream *_myds);
bool handle_command_query_kill(PtrSize_t *);
/**
* @brief Performs the final operations after current query has finished to be executed. It updates the session
* 'transaction_persistent_hostgroup', and updates the 'MySQL_Data_Stream' and 'MySQL_Connection' before
* returning the connection back to the connection pool. After this operation the session should be ready
* for handling new client connections.
*
* @param myds The 'MySQL_Data_Stream' which status should be updated.
* @param myconn The 'MySQL_Connection' which status should be updated, and which should be returned to
* the connection pool.
* @param prepared_stmt_with_no_params specifies if the processed query was a prepared statement with no
* params.
*/
void finishQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn, bool);
void generate_proxysql_internal_session_json(json &);
bool known_query_for_locked_on_hostgroup(uint64_t);
Expand Down
1 change: 0 additions & 1 deletion include/MySQL_Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,6 @@ class MySQL_Threads_Handler
int ping_timeout_server;
int shun_on_failures;
int shun_recovery_time_sec;
int unshun_algorithm;
int query_retries_on_failure;
bool client_multi_statements;
bool connection_warming;
Expand Down
4 changes: 1 addition & 3 deletions include/proxysql_admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,8 @@ class ProxySQL_Admin {
bool ProxySQL_Test___Verify_mysql_query_rules_fast_routing(int *ret1, int *ret2, int cnt, int dual);
void ProxySQL_Test___MySQL_HostGroups_Manager_generate_many_clusters();
unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_read_only_action();
#ifdef DEBUG
unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_HG_lookup();
unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211();
#endif

friend void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt);
};
#endif /* __CLASS_PROXYSQL_ADMIN_H */
5 changes: 3 additions & 2 deletions include/proxysql_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,6 @@ __thread int mysql_thread___ping_interval_server_msec;
__thread int mysql_thread___ping_timeout_server;
__thread int mysql_thread___shun_on_failures;
__thread int mysql_thread___shun_recovery_time_sec;
__thread int mysql_thread___unshun_algorithm;
__thread int mysql_thread___query_retries_on_failure;
__thread bool mysql_thread___client_multi_statements;
__thread int mysql_thread___connect_retries_on_failure;
Expand Down Expand Up @@ -906,7 +905,6 @@ extern __thread int mysql_thread___ping_interval_server_msec;
extern __thread int mysql_thread___ping_timeout_server;
extern __thread int mysql_thread___shun_on_failures;
extern __thread int mysql_thread___shun_recovery_time_sec;
extern __thread int mysql_thread___unshun_algorithm;
extern __thread int mysql_thread___query_retries_on_failure;
extern __thread bool mysql_thread___client_multi_statements;
extern __thread int mysql_thread___connect_retries_on_failure;
Expand Down Expand Up @@ -1053,6 +1051,9 @@ typedef struct {
char * default_value; // default value
bool is_global_variable; // is it a global variable?
} mysql_variable_st;

TODO: 'SQL_CHARACTER_SET_DATABASE' is a variable that shouldn't be set, or tracked on our side, since it's meant to be only updated by the server:
- https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_character_set_database
*/
mysql_variable_st mysql_tracked_variables[] {
{ SQL_CHARACTER_SET, SETTING_CHARSET, false, true, false, false, false, (char *)"charset", (char *)"charset", (char *)"utf8" , true} , // should be before SQL_CHARACTER_SET_RESULTS
Expand Down
105 changes: 7 additions & 98 deletions lib/MySQL_HostGroups_Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ MySrvC::MySrvC(char *add, uint16_t p, uint16_t gp, unsigned int _weight, enum My
ConnectionsFree=new MySrvConnList(this);
}

void MySrvC::connect_error(int err_num, bool get_mutex) {
void MySrvC::connect_error(int err_num) {
// NOTE: this function operates without any mutex
// although, it is not extremely important if any counter is lost
// as a single connection failure won't make a significant difference
Expand Down Expand Up @@ -901,7 +901,6 @@ void MySrvC::connect_error(int err_num, bool get_mutex) {
case 1120:
case 1203: // User %s already has more than 'max_user_connections' active connections
case 1226: // User '%s' has exceeded the '%s' resource (current value: %ld)
case 3118: // Access denied for user '%s'. Account is locked..
return;
break;
default:
Expand All @@ -921,17 +920,15 @@ void MySrvC::connect_error(int err_num, bool get_mutex) {
int max_failures = ( mysql_thread___shun_on_failures > mysql_thread___connect_retries_on_failure ? mysql_thread___connect_retries_on_failure : mysql_thread___shun_on_failures) ;
if (__sync_add_and_fetch(&connect_ERR_at_time_last_detected_error,1) >= (unsigned int)max_failures) {
bool _shu=false;
if (get_mutex==true)
MyHGM->wrlock(); // to prevent race conditions, lock here. See #627
MyHGM->wrlock(); // to prevent race conditions, lock here. See #627
if (status==MYSQL_SERVER_STATUS_ONLINE) {
status=MYSQL_SERVER_STATUS_SHUNNED;
shunned_automatic=true;
_shu=true;
} else {
_shu=false;
}
if (get_mutex==true)
MyHGM->wrunlock();
MyHGM->wrunlock();
if (_shu) {
proxy_error("Shunning server %s:%d with %u errors/sec. Shunning for %u seconds\n", address, port, connect_ERR_at_time_last_detected_error , mysql_thread___shun_recovery_time_sec);
}
Expand Down Expand Up @@ -2816,13 +2813,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
mysrvc->shunned_and_kill_all_connections=false;
mysrvc->connect_ERR_at_time_last_detected_error=0;
mysrvc->time_last_detected_error=0;
// note: the following function scans all the hostgroups.
// This is ok for now because we only have a global mutex.
// If one day we implement a mutex per hostgroup (unlikely,
// but possible), this must be taken into consideration
if (mysql_thread___unshun_algorithm == 1) {
MyHGM->unshun_server_all_hostgroups(mysrvc->address, mysrvc->port, t, max_wait_sec, &mysrvc->myhgc->hid);
}
// if a server is taken back online, consider it immediately
if ( mysrvc->current_latency_us < ( mysrvc->max_latency_us ? mysrvc->max_latency_us : mysql_thread___default_max_latency_ms*1000 ) ) { // consider the host only if not too far
if (gtid_trxid) {
Expand Down Expand Up @@ -2945,9 +2935,9 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
return NULL; // if we reach here, we couldn't find any target
}

/*
unsigned int New_sum=0;
unsigned int New_TotalUsedConn=0;

// we will now scan again to ignore overloaded servers
for (j=0; j<num_candidates; j++) {
mysrvc = mysrvcCandidates[j];
Expand All @@ -2965,9 +2955,7 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
num_candidates--;
}
}
*/

unsigned int New_sum=sum;

if (New_sum==0) {
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC NULL because no backend ONLINE or with weight\n");
Expand All @@ -2981,7 +2969,7 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
}

// latency awareness algorithm is enabled only when compiled with USE_MYSRVC_ARRAY
if (sess && sess->thread->variables.min_num_servers_lantency_awareness) {
if (sess->thread->variables.min_num_servers_lantency_awareness) {
if ((int) num_candidates >= sess->thread->variables.min_num_servers_lantency_awareness) {
unsigned int servers_with_latency = 0;
unsigned int total_latency_us = 0;
Expand Down Expand Up @@ -3234,47 +3222,6 @@ MySQL_Connection * MySrvConnList::get_random_MyConn(MySQL_Session *sess, bool ff
return NULL; // never reach here
}

void MySQL_HostGroups_Manager::unshun_server_all_hostgroups(const char * address, uint16_t port, time_t t, int max_wait_sec, unsigned int *skip_hid) {
// we scan all hostgroups looking for a specific server to unshun
// if skip_hid is not NULL , the specific hostgroup is skipped
int i, j;
for (i=0; i<(int)MyHostGroups->len; i++) {
MyHGC *myhgc=(MyHGC *)MyHostGroups->index(i);
if (skip_hid != NULL && myhgc->hid == *skip_hid) {
// if skip_hid is not NULL, we skip that specific hostgroup
continue;
}
bool found = false; // was this server already found in this hostgroup?
for (j=0; found==false && j<(int)myhgc->mysrvs->cnt(); j++) {
MySrvC *mysrvc=(MySrvC *)myhgc->mysrvs->servers->index(j);
if (mysrvc->status==MYSQL_SERVER_STATUS_SHUNNED) {
// we only care for SHUNNED nodes
// Note that we check for address and port only for status==MYSQL_SERVER_STATUS_SHUNNED ,
// that means that potentially we will pass by the matching node and still looping .
// This is potentially an optimization because we only check status and do not perform any strcmp()
if (strcmp(mysrvc->address,address)==0 && mysrvc->port==port) {
// we found the server in this hostgroup
// no need to process more servers in the same hostgroup
found = true;
if (t > mysrvc->time_last_detected_error && (t - mysrvc->time_last_detected_error) > max_wait_sec) {
if (
(mysrvc->shunned_and_kill_all_connections==false) // it is safe to bring it back online
||
(mysrvc->shunned_and_kill_all_connections==true && mysrvc->ConnectionsUsed->conns_length()==0 && mysrvc->ConnectionsFree->conns_length()==0) // if shunned_and_kill_all_connections is set, ensure all connections are already dropped
) {
mysrvc->status=MYSQL_SERVER_STATUS_ONLINE;
mysrvc->shunned_automatic=false;
mysrvc->shunned_and_kill_all_connections=false;
mysrvc->connect_ERR_at_time_last_detected_error=0;
mysrvc->time_last_detected_error=0;
}
}
}
}
}
}
}

MySQL_Connection * MySQL_HostGroups_Manager::get_MyConn_from_pool(unsigned int _hid, MySQL_Session *sess, bool ff, char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms) {
MySQL_Connection * conn=NULL;
wrlock();
Expand Down Expand Up @@ -3601,22 +3548,8 @@ int MySQL_HostGroups_Manager::get_multiple_idle_connections(int _hid, unsigned l
drop_all_idle_connections();
int num_conn_current=0;
int j,k;
MyHGC* myhgc = NULL;
for (int i=0; i<(int)MyHostGroups->len; i++) {
if (_hid == -1) {
// all hostgroups must be examined
// as of version 2.3.2 , this is always the case
myhgc=(MyHGC *)MyHostGroups->index(i);
} else {
// only one hostgroup is examined
// as of version 2.3.2 , this never happen
// but the code support this functionality
myhgc = MyHGC_find(_hid);
i = (int)MyHostGroups->len; // to exit from this "for" loop
if (myhgc == NULL)
continue; // immediately exit
}
if (_hid >= 0 && _hid!=(int)myhgc->hid) continue;
MyHGC* myhgc = MyHGC_find(_hid);
if (myhgc) {
for (j=0; j<(int)myhgc->mysrvs->cnt(); j++) {
MySrvC *mysrvc=(MySrvC *)myhgc->mysrvs->servers->index(j);
//PtrArray *pa=mysrvc->ConnectionsFree->conns;
Expand Down Expand Up @@ -7045,28 +6978,4 @@ void MySQL_HostGroups_Manager::update_aws_aurora_set_reader(int _whid, int _rhid
free(domain_name);
}

MySrvC* MySQL_HostGroups_Manager::find_server_in_hg(unsigned int _hid, const std::string& addr, int port) {
MySrvC* f_server = nullptr;

MyHGC* myhgc = nullptr;
for (uint32_t i = 0; i < MyHostGroups->len; i++) {
myhgc = static_cast<MyHGC*>(MyHostGroups->index(i));

if (myhgc->hid == _hid) {
break;
}
}

if (myhgc != nullptr) {
for (uint32_t j = 0; j < myhgc->mysrvs->cnt(); j++) {
MySrvC* mysrvc = static_cast<MySrvC*>(myhgc->mysrvs->servers->index(j));

if (strcmp(mysrvc->address, addr.c_str()) == 0 && mysrvc->port == port) {
f_server = mysrvc;
}
}
}

return f_server;
}

Loading