Skip to content

Commit c5aed61

Browse files
committed
MySQL: Track session-specific system variables changes
- Add new mysql variable `mysql-session_track_variables`. - Configure `session_track_system_variables` and `session_track_state_change` on backend connections if the mysql variable is enabled. - Utilize notifications from backend servers to capture system variable changes that cannot be handled by `MySQL_Set_Stmt_Parser` - Update both client and server variable maps based on backend responses. - TAP test to verify this patch. Signed-off-by: Wazir Ahmed <[email protected]>
1 parent dd847a1 commit c5aed61

11 files changed

+257
-6
lines changed

include/MySQL_Session.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,16 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
225225
bool handler_again___verify_ldap_user_variable();
226226
bool handler_again___verify_backend_autocommit();
227227
bool handler_again___verify_backend_session_track_gtids();
228+
bool handler_again___verify_backend_session_track_variables();
228229
bool handler_again___verify_backend_multi_statement();
229230
bool handler_again___verify_backend_user_schema();
230231
bool handler_again___verify_multiple_variables(MySQL_Connection *);
231232
bool handler_again___status_SETTING_INIT_CONNECT(int *);
232233
bool handler_again___status_SETTING_LDAP_USER_VARIABLE(int *);
233234
bool handler_again___status_SETTING_SQL_MODE(int *);
234235
bool handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *);
236+
bool handler_again___status_SETTING_SESSION_TRACK_VARIABLES(int *);
237+
bool handler_again___status_SETTING_SESSION_TRACK_STATE(int *);
235238
bool handler_again___status_CHANGING_CHARSET(int *_rc);
236239
bool handler_again___status_CHANGING_SCHEMA(int *);
237240
bool handler_again___status_CONNECTING_SERVER(int *);
@@ -280,6 +283,7 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
280283
int RunQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn);
281284
void handler___status_WAITING_CLIENT_DATA();
282285
void handler_rc0_Process_GTID(MySQL_Connection *myconn);
286+
void handler_rc0_Process_Variables(MySQL_Connection *myconn);
283287
void handler_rc0_RefreshActiveTransactions(MySQL_Connection* myconn);
284288
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_INIT_DB_replace_CLICKHOUSE(PtrSize_t& pkt);
285289
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY___not_mysql(PtrSize_t& pkt);

include/MySQL_Thread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,13 @@ struct th_metrics_map_idx {
328328
};
329329
};
330330

331+
struct session_track_variables {
332+
enum mode {
333+
DISABLED = 0,
334+
ENABLED
335+
};
336+
};
337+
331338
/**
332339
* @brief Structure holding the data for a Client_Host_Cache entry.
333340
*/
@@ -582,6 +589,7 @@ class MySQL_Threads_Handler
582589
int processlist_max_query_length;
583590

584591
bool ignore_min_gtid_annotations;
592+
int session_track_variables;
585593
} variables;
586594
struct {
587595
unsigned int mirror_sessions_current;

include/mysql_connection.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class MySQL_Connection {
8989
char *ldap_user_variable;
9090
char *ldap_user_variable_value;
9191
bool session_track_gtids_sent;
92+
bool session_track_variables_sent;
93+
bool session_track_state_sent;
9294
bool ldap_user_variable_sent;
9395
uint8_t protocol_version;
9496
int8_t last_set_autocommit;
@@ -262,6 +264,7 @@ class MySQL_Connection {
262264
void reset();
263265

264266
bool get_gtid(char *buff, uint64_t *trx_id);
267+
bool get_variables(std::unordered_map<std::string, std::string>&);
265268
void reduce_auto_increment_delay_token() { if (auto_increment_delay_token) auto_increment_delay_token--; };
266269

267270
bool match_ff_req_options(const MySQL_Connection *c);

include/proxysql_structs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ enum session_status {
311311
SETTING_NEXT_TRANSACTION_READ,
312312
PROCESSING_EXTENDED_QUERY_SYNC,
313313
RESYNCHRONIZING_CONNECTION,
314+
SETTING_SESSION_TRACK_VARIABLES,
315+
SETTING_SESSION_TRACK_STATE,
314316
session_status___NONE // special marker
315317
};
316318

@@ -1305,6 +1307,7 @@ __thread int mysql_thread___client_host_error_counts;
13051307
__thread int mysql_thread___handle_warnings;
13061308
__thread int mysql_thread___evaluate_replication_lag_on_servers_load;
13071309
__thread bool mysql_thread___ignore_min_gtid_annotations;
1310+
__thread int mysql_thread___session_track_variables;
13081311

13091312
/* variables used for Query Cache */
13101313
__thread int mysql_thread___query_cache_size_MB;
@@ -1609,6 +1612,7 @@ extern __thread int mysql_thread___client_host_error_counts;
16091612
extern __thread int mysql_thread___handle_warnings;
16101613
extern __thread int mysql_thread___evaluate_replication_lag_on_servers_load;
16111614
extern __thread bool mysql_thread___ignore_min_gtid_annotations;
1615+
extern __thread int mysql_thread___session_track_variables;
16121616

16131617
/* variables used for Query Cache */
16141618
extern __thread int mysql_thread___query_cache_size_MB;

lib/MySQL_Session.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,25 @@ bool MySQL_Session::handler_again___verify_backend_session_track_gtids() {
19571957
return ret;
19581958
}
19591959

1960+
bool MySQL_Session::handler_again___verify_backend_session_track_variables() {
1961+
if (mysql_thread___session_track_variables == session_track_variables::DISABLED) {
1962+
return false;
1963+
}
1964+
1965+
if (mybe->server_myds->myconn->options.session_track_variables_sent == false) {
1966+
mybe->server_myds->myconn->options.session_track_variables_sent = true;
1967+
set_previous_status_mode3();
1968+
NEXT_IMMEDIATE_NEW(SETTING_SESSION_TRACK_VARIABLES);
1969+
}
1970+
1971+
if (mybe->server_myds->myconn->options.session_track_state_sent == false) {
1972+
mybe->server_myds->myconn->options.session_track_state_sent = true;
1973+
set_previous_status_mode3();
1974+
NEXT_IMMEDIATE_NEW(SETTING_SESSION_TRACK_STATE);
1975+
}
1976+
1977+
return false;
1978+
}
19601979

19611980
bool MySQL_Session::handler_again___verify_multiple_variables(MySQL_Connection* myconn) {
19621981
for (auto i = 0; i < SQL_NAME_LAST_LOW_WM; i++) {
@@ -2757,6 +2776,20 @@ bool MySQL_Session::handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *_rc)
27572776
return ret;
27582777
}
27592778

2779+
bool MySQL_Session::handler_again___status_SETTING_SESSION_TRACK_VARIABLES(int *_rc) {
2780+
bool ret=false;
2781+
assert(mybe->server_myds->myconn);
2782+
ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"session_track_system_variables", "*", false);
2783+
return ret;
2784+
}
2785+
2786+
bool MySQL_Session::handler_again___status_SETTING_SESSION_TRACK_STATE(int *_rc) {
2787+
bool ret=false;
2788+
assert(mybe->server_myds->myconn);
2789+
ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"session_track_state_change", "ON", false);
2790+
return ret;
2791+
}
2792+
27602793
bool MySQL_Session::handler_again___status_CHANGING_SCHEMA(int *_rc) {
27612794
bool ret=false;
27622795
//fprintf(stderr,"CHANGING_SCHEMA\n");
@@ -4898,6 +4931,41 @@ void MySQL_Session::handler_rc0_Process_GTID(MySQL_Connection *myconn) {
48984931
}
48994932
}
49004933

4934+
void MySQL_Session::handler_rc0_Process_Variables(MySQL_Connection *myconn) {
4935+
std::unordered_map<string, string> var_map;
4936+
4937+
if(myconn->get_variables(var_map)) {
4938+
std::string variable;
4939+
std::string value;
4940+
4941+
for (int idx = 0 ; idx < SQL_NAME_LAST_HIGH_WM ; idx++) {
4942+
variable = mysql_tracked_variables[idx].set_variable_name;
4943+
4944+
auto itr = var_map.find(variable);
4945+
if(itr != var_map.end()) {
4946+
value = itr->second;
4947+
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 7, "Session=%p, backend=%p. Notification for session_track_system_variables: variable=%s, value=%s\n", this, this->mybe, variable.c_str(), value.c_str());
4948+
4949+
const MARIADB_CHARSET_INFO *ci = NULL;
4950+
if (variable == "character_set_results" || variable == "character_set_connection" ||
4951+
variable == "character_set_client" || variable == "character_set_database") {
4952+
ci = proxysql_find_charset_name(value.c_str());
4953+
}
4954+
else if (variable == "collation_connection") {
4955+
ci = proxysql_find_charset_collate(value.c_str());
4956+
}
4957+
4958+
if (ci) {
4959+
value = std::to_string(ci->nr);
4960+
}
4961+
4962+
mysql_variables.client_set_value(this, idx, value);
4963+
mysql_variables.server_set_value(this, idx, value.c_str());
4964+
}
4965+
}
4966+
}
4967+
}
4968+
49014969
void MySQL_Session::handler_KillConnectionIfNeeded() {
49024970
if ( // two conditions
49034971
// If the server connection is in a non-idle state (ASYNC_IDLE), and the current time is greater than or equal to mybe->server_myds->wait_until
@@ -5095,6 +5163,10 @@ int MySQL_Session::handler() {
50955163
goto handler_again;
50965164
}
50975165

5166+
if (handler_again___verify_backend_session_track_variables()) {
5167+
goto handler_again;
5168+
}
5169+
50985170
// Optimize network traffic when we can use 'SET NAMES'
50995171
if (verify_set_names(this)) {
51005172
goto handler_again;
@@ -5175,6 +5247,8 @@ int MySQL_Session::handler() {
51755247

51765248
handler_rc0_Process_GTID(myconn);
51775249

5250+
handler_rc0_Process_Variables(myconn);
5251+
51785252
// if we are locked on hostgroup, the value of autocommit is copied from the backend connection
51795253
// see bug #3549
51805254
if (locked_on_hostgroup >= 0) {
@@ -5471,6 +5545,12 @@ bool MySQL_Session::handler_again___multiple_statuses(int *rc) {
54715545
case SETTING_SESSION_TRACK_GTIDS:
54725546
ret = handler_again___status_SETTING_SESSION_TRACK_GTIDS(rc);
54735547
break;
5548+
case SETTING_SESSION_TRACK_VARIABLES:
5549+
ret = handler_again___status_SETTING_SESSION_TRACK_VARIABLES(rc);
5550+
break;
5551+
case SETTING_SESSION_TRACK_STATE:
5552+
ret = handler_again___status_SETTING_SESSION_TRACK_STATE(rc);
5553+
break;
54745554
case SETTING_SET_NAMES:
54755555
ret = handler_again___status_CHANGING_CHARSET(rc);
54765556
break;

lib/MySQL_Thread.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ static char * mysql_thread_variables_names[]= {
512512
(char *)"protocol_compression_level",
513513
(char *)"ignore_min_gtid_annotations",
514514
(char *)"fast_forward_grace_close_ms",
515+
(char *)"session_track_variables",
515516
NULL
516517
};
517518

@@ -1156,6 +1157,8 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() {
11561157
variables.data_packets_history_size=0;
11571158
variables.protocol_compression_level=3;
11581159
variables.ignore_min_gtid_annotations=false;
1160+
variables.session_track_variables=session_track_variables::DISABLED;
1161+
11591162
// status variables
11601163
status_variables.mirror_sessions_current=0;
11611164
__global_MySQL_Thread_Variables_version=1;
@@ -2336,7 +2339,7 @@ char ** MySQL_Threads_Handler::get_variables_list() {
23362339
VariablesPointers_int["eventslog_format"] = make_tuple(&variables.eventslog_format, 0, 0, true);
23372340
VariablesPointers_int["wait_timeout"] = make_tuple(&variables.wait_timeout, 0, 0, true);
23382341
VariablesPointers_int["data_packets_history_size"] = make_tuple(&variables.data_packets_history_size, 0, 0, true);
2339-
2342+
VariablesPointers_int["session_track_variables"] = make_tuple(&variables.session_track_variables, 0, 1, false);
23402343
}
23412344

23422345

@@ -4310,6 +4313,7 @@ void MySQL_Thread::refresh_variables() {
43104313
REFRESH_VARIABLE_INT(handle_warnings);
43114314
REFRESH_VARIABLE_INT(evaluate_replication_lag_on_servers_load);
43124315
REFRESH_VARIABLE_BOOL(ignore_min_gtid_annotations);
4316+
REFRESH_VARIABLE_INT(session_track_variables);
43134317
#ifdef DEBUG
43144318
REFRESH_VARIABLE_BOOL(session_debug);
43154319
#endif /* DEBUG */

lib/mysql_connection.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ MySQL_Connection::MySQL_Connection() {
452452
options.init_connect_sent=false;
453453
options.session_track_gtids = NULL;
454454
options.session_track_gtids_sent = false;
455+
options.session_track_variables_sent = false;
456+
options.session_track_state_sent = false;
455457
options.ldap_user_variable=NULL;
456458
options.ldap_user_variable_value=NULL;
457459
options.ldap_user_variable_sent=false;
@@ -3082,6 +3084,8 @@ void MySQL_Connection::reset() {
30823084
options.session_track_gtids = NULL;
30833085
options.session_track_gtids_sent = false;
30843086
}
3087+
options.session_track_variables_sent = false;
3088+
options.session_track_state_sent = false;
30853089
}
30863090

30873091
bool MySQL_Connection::get_gtid(char *buff, uint64_t *trx_id) {
@@ -3116,6 +3120,46 @@ bool MySQL_Connection::get_gtid(char *buff, uint64_t *trx_id) {
31163120
return ret;
31173121
}
31183122

3123+
bool MySQL_Connection::get_variables(std::unordered_map<string, string>& variables) {
3124+
bool ret = false;
3125+
3126+
if ((mysql != nullptr)
3127+
&& (mysql->net.last_errno == 0)
3128+
&& (mysql->server_status & SERVER_SESSION_STATE_CHANGED)) {
3129+
// when there is no error and status changed
3130+
const char *data;
3131+
size_t length;
3132+
3133+
if (mysql_session_track_get_first(mysql, SESSION_TRACK_SYSTEM_VARIABLES, &data, &length) == 0) {
3134+
string var_name(data, length);
3135+
string val;
3136+
3137+
// get_first() returns a variable_name
3138+
// get_next() will return the value
3139+
bool expect_value = true;
3140+
3141+
while (mysql_session_track_get_next(mysql, SESSION_TRACK_SYSTEM_VARIABLES, &data, &length) == 0) {
3142+
if (expect_value) {
3143+
val = string(data, length);
3144+
variables[var_name] = val;
3145+
// got a value in this iteration
3146+
// in the next iteration, we have to expect a variable_name
3147+
expect_value = false;
3148+
} else {
3149+
var_name = string(data, length);
3150+
// got a variable_name in this iteration
3151+
// in the next iteration, we have to expect the value of this variable
3152+
expect_value = true;
3153+
}
3154+
}
3155+
3156+
ret = true;
3157+
}
3158+
}
3159+
3160+
return ret;
3161+
}
3162+
31193163
void MySQL_Connection::set_ssl_params(MYSQL *mysql, MySQLServers_SslParams *ssl_params) {
31203164
if (ssl_params == NULL) {
31213165
mysql_ssl_set(mysql,

test/tap/groups/groups.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,6 @@
233233
"test_ssl_fast_forward-2_libmysql-t": [ "default-g4", "mysql-auto_increment_delay_multiplex=0-g4", "mysql-multiplexing=false-g4", "mysql-query_digests=0-g4", "mysql-query_digests_keep_comment=1-g4" ],
234234
"test_ssl_fast_forward-3_libmariadb-t": [ "default-g4", "mysql-auto_increment_delay_multiplex=0-g4", "mysql-multiplexing=false-g4", "mysql-query_digests=0-g4", "mysql-query_digests_keep_comment=1-g4" ],
235235
"test_ssl_fast_forward-3_libmysql-t": [ "default-g4", "mysql-auto_increment_delay_multiplex=0-g4", "mysql-multiplexing=false-g4", "mysql-query_digests=0-g4", "mysql-query_digests_keep_comment=1-g4" ],
236-
"test_ignore_min_gtid-t": [ "default-g4", "mysql-auto_increment_delay_multiplex=0-g4", "mysql-multiplexing=false-g4", "mysql-query_digests=0-g4", "mysql-query_digests_keep_comment=1-g4" ]
236+
"test_ignore_min_gtid-t": [ "default-g4", "mysql-auto_increment_delay_multiplex=0-g4", "mysql-multiplexing=false-g4", "mysql-query_digests=0-g4", "mysql-query_digests_keep_comment=1-g4" ],
237+
"mysql-track_system_variables-t" : [ "default-g4","mysql-auto_increment_delay_multiplex=0-g4","mysql-multiplexing=false-g4","mysql-query_digests=0-g4","mysql-query_digests_keep_comment=1-g4" ]
237238
}

0 commit comments

Comments
 (0)