Skip to content

Commit 47f344f

Browse files
committed
Enable session tracking based on server capabilities
Signed-off-by: Wazir Ahmed <[email protected]>
1 parent a0cffd8 commit 47f344f

File tree

9 files changed

+125
-14
lines changed

9 files changed

+125
-14
lines changed

include/MySQL_HostGroups_Manager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ class MySrvC { // MySQL Server Container
227227
bool shunned_and_kill_all_connections; // if a serious failure is detected, this will cause all connections to die even if the server is just shunned
228228
int32_t use_ssl;
229229
char *comment;
230+
231+
// 'server_backoff_time' stores a timestamp that prevents the server from being
232+
// considered for random selection ('MyHGC::get_random_MySrvC') until that time passes.
233+
//
234+
// This is primarily used when `session_track_variables::ENFORCED` mode is active.
235+
// If a server lacks the required capabilities in this mode, it is temporarily
236+
// excluded from selection for a specified duration.
237+
unsigned long long server_backoff_time;
238+
230239
MySrvConnList *ConnectionsUsed;
231240
MySrvConnList *ConnectionsFree;
232241
/**

include/MySQL_Session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
554554
void reset_warning_hostgroup_flag_and_release_connection();
555555
void set_previous_status_mode3(bool allow_execute=true);
556556
char* get_current_query(int max_length = -1);
557+
bool handle_session_track_capabilities();
557558

558559
friend void SQLite3_Server_session_handler(MySQL_Session*, void *_pa, PtrSize_t *pkt);
559560

include/MySQL_Thread.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,13 @@ struct th_metrics_map_idx {
367367
*/
368368
struct session_track_variables {
369369
enum mode {
370-
DISABLED = 0, ///< Session variable tracking is disabled (default)
371-
ENABLED ///< Session variable tracking is enabled
370+
// Disabled; default mode
371+
DISABLED = 0,
372+
// Enable session tracking if backend supports it
373+
OPTIONAL,
374+
// Enforce session tracking; connection fails if backend does
375+
// not support CLIENT_DEPRECATE_EOF and CLIENT_SESSION_TRACKING
376+
ENFORCED
372377
};
373378
};
374379

lib/MyHGC.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
3838
for (j=0; j<l; j++) {
3939
mysrvc=mysrvs->idx(j);
4040
if (mysrvc->get_status() == MYSQL_SERVER_STATUS_ONLINE) { // consider this server only if ONLINE
41+
// skip servers that are in backoff period
42+
if (mysrvc->server_backoff_time > sess->thread->curtime)
43+
continue;
44+
4145
if (mysrvc->myhgc->num_online_servers.load(std::memory_order_relaxed) <= mysrvc->myhgc->attributes.max_num_online_servers) { // number of online servers in HG is within configured range
4246
if (mysrvc->ConnectionsUsed->conns_length() < mysrvc->max_connections) { // consider this server only if didn't reach max_connections
4347
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

lib/MySQL_Protocol.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,9 +1111,13 @@ bool MySQL_Protocol::generate_pkt_initial_handshake(bool send, void **ptr, unsig
11111111
// variable. This is the first step of ensuring that client connections doesn't
11121112
// enable 'CLIENT_DEPRECATE_EOF' unless explicitly stated by 'mysql-enable_client_deprecate_eof'.
11131113
// Second step occurs during client handshake response (process_pkt_handshake_response).
1114-
if (deprecate_eof_active && mysql_thread___enable_client_deprecate_eof) {
1115-
extended_capabilities |= CLIENT_DEPRECATE_EOF;
1114+
if (deprecate_eof_active) {
1115+
if (mysql_thread___enable_client_deprecate_eof
1116+
|| mysql_thread___session_track_variables == session_track_variables::ENFORCED) {
1117+
extended_capabilities |= CLIENT_DEPRECATE_EOF;
1118+
}
11161119
}
1120+
11171121
// Copy the 'capability_flags_2'
11181122
uint16_t upper_word = static_cast<uint16_t>(extended_capabilities >> 16);
11191123
memcpy(_ptr+l, static_cast<void*>(&upper_word), sizeof(upper_word)); l += sizeof(upper_word);

lib/MySQL_Session.cpp

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,10 +1915,12 @@ bool MySQL_Session::handler_again___verify_backend_session_track_gtids() {
19151915
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.session_track_gtids, mybe->server_myds->myconn->options.session_track_gtids);
19161916
// we first verify that the backend supports it
19171917
// if backend is old (or if it is not mysql) ignore this setting
1918-
if ((mybe->server_myds->myconn->mysql->server_capabilities & CLIENT_SESSION_TRACKING) == 0) {
1919-
// the backend doesn't support CLIENT_SESSION_TRACKING
1920-
return ret; // exit immediately
1918+
if ((mybe->server_myds->myconn->mysql->server_capabilities & CLIENT_SESSION_TRACKING) == 0
1919+
|| (mybe->server_myds->myconn->mysql->server_capabilities & CLIENT_DEPRECATE_EOF) == 0
1920+
|| mysql_thread___enable_server_deprecate_eof == false) {
1921+
return ret;
19211922
}
1923+
19221924
uint32_t b_int = mybe->server_myds->myconn->options.session_track_gtids_int;
19231925
uint32_t f_int = client_myds->myconn->options.session_track_gtids_int;
19241926

@@ -1965,16 +1967,26 @@ bool MySQL_Session::handler_again___verify_backend_session_track_gtids() {
19651967
}
19661968

19671969
bool MySQL_Session::handler_again___verify_backend_session_track_variables() {
1968-
if (mysql_thread___session_track_variables == session_track_variables::DISABLED) {
1970+
int mode = mysql_thread___session_track_variables;
1971+
1972+
// skip enabling session variable tracking in the following cases
1973+
if (mode == session_track_variables::DISABLED) {
1974+
return false;
1975+
}
1976+
if ((mybe->server_myds->myconn->mysql->server_capabilities & CLIENT_SESSION_TRACKING) == 0
1977+
|| (mybe->server_myds->myconn->mysql->server_capabilities & CLIENT_DEPRECATE_EOF) == 0) {
1978+
return false;
1979+
}
1980+
if (!mysql_thread___enable_server_deprecate_eof && mode != session_track_variables::ENFORCED) {
19691981
return false;
19701982
}
19711983

1984+
// enable session tracking
19721985
if (mybe->server_myds->myconn->options.session_track_variables_sent == false) {
19731986
mybe->server_myds->myconn->options.session_track_variables_sent = true;
19741987
set_previous_status_mode3();
19751988
NEXT_IMMEDIATE_NEW(SETTING_SESSION_TRACK_VARIABLES);
19761989
}
1977-
19781990
if (mybe->server_myds->myconn->options.session_track_state_sent == false) {
19791991
mybe->server_myds->myconn->options.session_track_state_sent = true;
19801992
set_previous_status_mode3();
@@ -2944,6 +2956,11 @@ bool MySQL_Session::handler_again___status_CONNECTING_SERVER(int *_rc) {
29442956
}
29452957
enum session_status st=status;
29462958
if (mybe->server_myds->myconn->async_state_machine==ASYNC_IDLE) {
2959+
if (handle_session_track_capabilities() == false) {
2960+
pause_until = thread->curtime + mysql_thread___connect_retries_delay*1000;
2961+
return false;
2962+
}
2963+
29472964
st=previous_status.top();
29482965
previous_status.pop();
29492966
NEXT_IMMEDIATE_NEW(st);
@@ -2973,6 +2990,13 @@ bool MySQL_Session::handler_again___status_CONNECTING_SERVER(int *_rc) {
29732990
previous_status.pop();
29742991
myds->wait_until=0;
29752992

2993+
if (handle_session_track_capabilities() == false) {
2994+
previous_status.push(st);
2995+
pause_until = thread->curtime + mysql_thread___connect_retries_delay * 1000;
2996+
set_status(CONNECTING_SERVER);
2997+
return false;
2998+
}
2999+
29763000
// NOTE: Even if a connection has correctly been created, since the CLIENT_DEPRECATE_EOF
29773001
// capability isn't always enforced to match for backend conns (no direct propagation), a
29783002
// mismatch can take place after the creation. Right now this is only true for
@@ -8377,3 +8401,57 @@ char* MySQL_Session::get_current_query(int max_length) {
83778401

83788402
return res;
83798403
}
8404+
8405+
/**
8406+
* @brief Handle session track capabilities validation.
8407+
*
8408+
* This function validates whether the backend connection has capabilities such as 'CLIENT_DEPRECATE_EOF'
8409+
* and 'CLIENT_SESSION_TRACKING' which are required to enable 'session_track_system_variables' in a MySQL session.
8410+
*
8411+
* If the connection lacks the capabilities and ProxySQL configuration is set in 'ENFORCED' mode, it returns the
8412+
* connection to the pool and set a backoff time for the backend server. This backoff time prevents the server from
8413+
* being selected again during connection pooling.
8414+
*
8415+
* @return 'true' if backend connection has required capabilities, otherwise returns 'false'.
8416+
*/
8417+
bool MySQL_Session::handle_session_track_capabilities() {
8418+
if (mysql_thread___session_track_variables != session_track_variables::ENFORCED) {
8419+
return true;
8420+
}
8421+
8422+
// this function should not be called in these states
8423+
if (client_myds == NULL
8424+
|| client_myds->myconn == NULL
8425+
|| mybe == NULL
8426+
|| mybe->server_myds == NULL
8427+
|| mybe->server_myds->myconn == NULL
8428+
|| mybe->server_myds->myconn->mysql == NULL) {
8429+
return true;
8430+
}
8431+
8432+
MySQL_Connection *be_conn = mybe->server_myds->myconn;
8433+
unsigned long srv_cap = be_conn->mysql->server_capabilities;
8434+
uint32_t client_flag = client_myds->myconn->options.client_flag;
8435+
8436+
bool client_support_session_track = ((client_flag & CLIENT_SESSION_TRACKING) != 0 && (client_flag & CLIENT_DEPRECATE_EOF) != 0);
8437+
bool server_support_session_track = ((srv_cap & CLIENT_SESSION_TRACKING) != 0 && (srv_cap & CLIENT_DEPRECATE_EOF) != 0);
8438+
8439+
// In fast forward, if client does not support session tracking,
8440+
// then ProxySQL do not have to enforce session track on backend connections
8441+
if ((session_fast_forward == SESSION_FORWARD_TYPE_PERMANENT) && !client_support_session_track) {
8442+
return true;
8443+
}
8444+
8445+
if (!server_support_session_track) {
8446+
// be_conn->parent->server_backoff_time = thread->curtime + (600 * 1000000); // 10 minutes
8447+
be_conn->parent->server_backoff_time = thread->curtime + (30 * 1000000); // 30 seconds
8448+
if (session_fast_forward) {
8449+
mybe->server_myds->destroy_MySQL_Connection_From_Pool(false);
8450+
} else {
8451+
mybe->server_myds->return_MySQL_Connection_To_Pool();
8452+
}
8453+
return false;
8454+
}
8455+
8456+
return true;
8457+
}

lib/MySQL_Thread.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,7 +2353,7 @@ char ** MySQL_Threads_Handler::get_variables_list() {
23532353
VariablesPointers_int["eventslog_format"] = make_tuple(&variables.eventslog_format, 0, 0, true);
23542354
VariablesPointers_int["wait_timeout"] = make_tuple(&variables.wait_timeout, 0, 0, true);
23552355
VariablesPointers_int["data_packets_history_size"] = make_tuple(&variables.data_packets_history_size, 0, 0, true);
2356-
VariablesPointers_int["session_track_variables"] = make_tuple(&variables.session_track_variables, 0, 1, false);
2356+
VariablesPointers_int["session_track_variables"] = make_tuple(&variables.session_track_variables, 0, 2, false);
23572357
}
23582358

23592359

@@ -5672,7 +5672,11 @@ MySQL_Connection * MySQL_Thread::get_MyConn_local(unsigned int _hid, MySQL_Sessi
56725672
std::vector<MySrvC *> parents; // this is a vector of srvers that needs to be excluded in case gtid_uuid is used
56735673
MySQL_Connection *c=NULL;
56745674
for (i=0; i<cached_connections->len; i++) {
5675-
c=(MySQL_Connection *)cached_connections->index(i);
5675+
c = (MySQL_Connection *) cached_connections->index(i);
5676+
// skip servers that are in backoff period
5677+
if (c->parent->server_backoff_time > curtime)
5678+
continue;
5679+
56765680
if (c->parent->myhgc->hid==_hid && sess->client_myds->myconn->match_tracked_options(c)) { // options are all identical
56775681
if (
56785682
(gtid_uuid == NULL) || // gtid_uuid is not used

lib/MySrvC.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ MySrvC::MySrvC(
3131
bytes_recv=0;
3232
max_connections_used=0;
3333
queries_gtid_sync=0;
34+
server_backoff_time = 0;
3435
time_last_detected_error=0;
3536
connect_ERR_at_time_last_detected_error=0;
3637
shunned_automatic=false;

lib/mysql_connection.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,13 +889,18 @@ void MySQL_Connection::connect_start_SetClientFlag(unsigned long& client_flags)
889889
}
890890
}
891891

892-
// set 'CLIENT_DEPRECATE_EOF' flag if explicitly stated by 'mysql-enable_server_deprecate_eof'.
893-
// Capability is disabled by default in 'mariadb_client', so setting this option is not optional
894-
// for having 'CLIENT_DEPRECATE_EOF' in the connection to be stablished.
892+
// 'CLIENT_DEPRECATE_EOF' capability is disabled by default in mariadb_client.
893+
// Based on the value of 'mysql-enable_server_deprecate_eof', enable this
894+
// capability in a new connection.
895895
if (mysql_thread___enable_server_deprecate_eof) {
896896
mysql->options.client_flag |= CLIENT_DEPRECATE_EOF;
897897
}
898898

899+
// override 'mysql-enable_server_deprecate_eof' behavior if 'session_track_variables' is set to 'ENFORCED'
900+
if (mysql_thread___session_track_variables == session_track_variables::ENFORCED) {
901+
mysql->options.client_flag |= CLIENT_DEPRECATE_EOF;
902+
}
903+
899904
if (myds != NULL) {
900905
if (myds->sess != NULL) {
901906
if (myds->sess->session_fast_forward) { // this is a fast_forward connection

0 commit comments

Comments
 (0)