From 7955dd21a8aae1c88c61d4f02f45f2f4734df44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 8 Apr 2025 16:29:39 +0200 Subject: [PATCH] Fix MySQL 8.4 replication lag monitoring - Closes #4727 Added support for new syntax to simulator. --- include/proxysql_structs.h | 3 +++ lib/ClickHouse_Server.cpp | 2 ++ lib/MySQL_Monitor.cpp | 37 ++++++++++++++++++++++++++--------- lib/MySQL_Query_Processor.cpp | 15 ++++++++++++++ src/SQLite3_Server.cpp | 26 +++++++++++++----------- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index 2450e8a82..5927ce81d 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -487,6 +487,7 @@ enum MYSQL_COM_QUERY_command { MYSQL_COM_QUERY_BEGIN, MYSQL_COM_QUERY_CALL, MYSQL_COM_QUERY_CHANGE_MASTER, + MYSQL_COM_QUERY_CHANGE_REPLICATION_SOURCE, MYSQL_COM_QUERY_COMMIT, MYSQL_COM_QUERY_CREATE_DATABASE, MYSQL_COM_QUERY_CREATE_INDEX, @@ -518,7 +519,9 @@ enum MYSQL_COM_QUERY_command { MYSQL_COM_QUERY_RELEASE_SAVEPOINT, MYSQL_COM_QUERY_RENAME_TABLE, MYSQL_COM_QUERY_RESET_MASTER, + MYSQL_COM_QUERY_RESET_BINARY_LOGS_AND_GTIDS, MYSQL_COM_QUERY_RESET_SLAVE, + MYSQL_COM_QUERY_RESET_REPLICA, MYSQL_COM_QUERY_REPLACE, MYSQL_COM_QUERY_REVOKE, MYSQL_COM_QUERY_ROLLBACK, diff --git a/lib/ClickHouse_Server.cpp b/lib/ClickHouse_Server.cpp index f8b005e5f..5f90568b0 100644 --- a/lib/ClickHouse_Server.cpp +++ b/lib/ClickHouse_Server.cpp @@ -1146,6 +1146,8 @@ __end_show_commands: || (strncasecmp("SHOW SLAVE STATUS",query_no_space,17)==0) || + (strncasecmp("SHOW REPLICA STATUS",query_no_space,19)==0) + || (strncasecmp("SHOW MASTER LOGS",query_no_space,16)==0) ) { GloClickHouseServer->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Access Denied"); diff --git a/lib/MySQL_Monitor.cpp b/lib/MySQL_Monitor.cpp index 4b8b83144..579a4006f 100644 --- a/lib/MySQL_Monitor.cpp +++ b/lib/MySQL_Monitor.cpp @@ -683,8 +683,12 @@ void MySQL_Monitor_State_Data::init_async() { case MON_REPLICATION_LAG: async_state_machine_ = ASYNC_QUERY_START; #ifdef TEST_REPLICATIONLAG - query_ = "SELECT SLAVE STATUS "; // replaced SHOW with SELECT to avoid breaking simulator logic - query_ += std::string(hostname) + ":" + std::to_string(port); + // Simulator syntax allows 'SELECT STATUS' + { + const std::string REPLICA { mysql_get_server_version(mysql) < 80023 ? "SLAVE" : "REPLICA" }; + query_ = "SELECT " + REPLICA + " STATUS "; + query_ += std::string(hostname) + ":" + std::to_string(port); + } #else if (mysql_thread___monitor_replication_lag_use_percona_heartbeat && mysql_thread___monitor_replication_lag_use_percona_heartbeat[0] != '\0') { @@ -692,7 +696,11 @@ void MySQL_Monitor_State_Data::init_async() { query_ = "SELECT MAX(ROUND(TIMESTAMPDIFF(MICROSECOND, ts, SYSDATE(6))/1000000)) AS Seconds_Behind_Master FROM "; query_ += mysql_thread___monitor_replication_lag_use_percona_heartbeat; } else { - query_ = "SHOW SLAVE STATUS"; + if (mysql_get_server_version(mysql) < 80023) { + query_ = "SHOW SLAVE STATUS"; + } else { + query_ = "SHOW REPLICA STATUS"; + } } #endif task_timeout_ = mysql_thread___monitor_replication_lag_timeout; @@ -2694,9 +2702,11 @@ void * monitor_replication_lag_thread(void *arg) { #ifdef TEST_REPLICATIONLAG { - std::string s = "SELECT SLAVE STATUS "; // replaced SHOW with SELECT to avoid breaking simulator logic - s += std::string(mmsd->hostname) + ":" + std::to_string(mmsd->port); - mmsd->async_exit_status = mysql_query_start(&mmsd->interr, mmsd->mysql, s.c_str()); + const string REPLICA { mysql_get_server_version(mmsd->mysql) < 80023 ? "SLAVE" : "REPLICA" }; + const string SELECT { + "SELECT " + REPLICA + " STATUS " + string(mmsd->hostname) + ":" + std::to_string(mmsd->port) + }; + mmsd->async_exit_status = mysql_query_start(&mmsd->interr, mmsd->mysql, SELECT.c_str()); } #else if (percona_heartbeat_table) { @@ -2711,7 +2721,10 @@ void * monitor_replication_lag_thread(void *arg) { } } if (use_percona_heartbeat == false) { - mmsd->async_exit_status=mysql_query_start(&mmsd->interr,mmsd->mysql,"SHOW SLAVE STATUS"); + const char* query { + mysql_get_server_version(mmsd->mysql) < 80023 ? "SHOW SLAVE STATUS" : "SHOW REPLICA STATUS" + }; + mmsd->async_exit_status=mysql_query_start(&mmsd->interr,mmsd->mysql, query); } #endif // TEST_REPLICATIONLAG while (mmsd->async_exit_status) { @@ -2819,7 +2832,10 @@ __exit_monitor_replication_lag_thread: { for(k = 0; k < num_fields; k++) { if (fields[k].name) { - if (strcmp("Seconds_Behind_Master", fields[k].name)==0) { + if ( + strcmp("Seconds_Behind_Master", fields[k].name)==0 + || strcmp("Seconds_Behind_Source", fields[k].name)==0 + ) { j=k; } } @@ -7909,7 +7925,10 @@ bool MySQL_Monitor::monitor_replication_lag_process_ready_tasks(const std::vecto { for (k = 0; k < num_fields; k++) { if (fields[k].name) { - if (strcmp("Seconds_Behind_Master", fields[k].name) == 0) { + if ( + strcmp("Seconds_Behind_Master", fields[k].name)==0 + || strcmp("Seconds_Behind_Source", fields[k].name)==0 + ) { j = k; } } diff --git a/lib/MySQL_Query_Processor.cpp b/lib/MySQL_Query_Processor.cpp index 561fd3084..b81f8650e 100644 --- a/lib/MySQL_Query_Processor.cpp +++ b/lib/MySQL_Query_Processor.cpp @@ -24,6 +24,7 @@ static char* commands_counters_desc[MYSQL_COM_QUERY___NONE] = { [MYSQL_COM_QUERY_BEGIN] = (char*)"BEGIN", [MYSQL_COM_QUERY_CALL] = (char*)"CALL", [MYSQL_COM_QUERY_CHANGE_MASTER] = (char*)"CHANGE_MASTER", + [MYSQL_COM_QUERY_CHANGE_REPLICATION_SOURCE] = (char*)"MYSQL_COM_QUERY_CHANGE_REPLICATION_SOURCE", [MYSQL_COM_QUERY_COMMIT] = (char*)"COMMIT", [MYSQL_COM_QUERY_CREATE_DATABASE] = (char*)"CREATE_DATABASE", [MYSQL_COM_QUERY_CREATE_INDEX] = (char*)"CREATE_INDEX", @@ -55,7 +56,9 @@ static char* commands_counters_desc[MYSQL_COM_QUERY___NONE] = { [MYSQL_COM_QUERY_RELEASE_SAVEPOINT] = (char*)"RELEASE_SAVEPOINT", [MYSQL_COM_QUERY_RENAME_TABLE] = (char*)"RENAME_TABLE", [MYSQL_COM_QUERY_RESET_MASTER] = (char*)"RESET_MASTER", + [MYSQL_COM_QUERY_RESET_BINARY_LOGS_AND_GTIDS] = (char*)"RESET_BINARY_LOGS_AND_GTIDS", [MYSQL_COM_QUERY_RESET_SLAVE] = (char*)"RESET_SLAVE", + [MYSQL_COM_QUERY_RESET_REPLICA] = (char*)"RESET_REPLICA", [MYSQL_COM_QUERY_REPLACE] = (char*)"REPLACE", [MYSQL_COM_QUERY_REVOKE] = (char*)"REVOKE", [MYSQL_COM_QUERY_ROLLBACK] = (char*)"ROLLBACK", @@ -263,6 +266,10 @@ __remove_paranthesis: ret = MYSQL_COM_QUERY_CHANGE_MASTER; break; } + if (!strcasecmp("REPLICATION", token)) { + ret = MYSQL_COM_QUERY_CHANGE_REPLICATION_SOURCE; + break; + } break; } if (!strcasecmp("COMMIT", token)) { // COMMIT @@ -442,10 +449,18 @@ __remove_paranthesis: ret = MYSQL_COM_QUERY_RESET_MASTER; break; } + if (!strcasecmp("BINARY", token)) { + ret = MYSQL_COM_QUERY_RESET_BINARY_LOGS_AND_GTIDS; + break; + } if (!strcasecmp("SLAVE", token)) { ret = MYSQL_COM_QUERY_RESET_SLAVE; break; } + if (!strcasecmp("REPLICA", token)) { + ret = MYSQL_COM_QUERY_RESET_REPLICA; + break; + } break; } if (!strcasecmp("REVOKE", token)) { // REVOKE diff --git a/src/SQLite3_Server.cpp b/src/SQLite3_Server.cpp index da0949520..f283f454d 100644 --- a/src/SQLite3_Server.cpp +++ b/src/SQLite3_Server.cpp @@ -871,7 +871,13 @@ __run_query: } #endif // TEST_READONLY #ifdef TEST_REPLICATIONLAG - if (strncasecmp("SELECT SLAVE STATUS ", query_no_space, strlen("SELECT SLAVE STATUS ")) == 0) { + if ( + strncasecmp("SELECT SLAVE STATUS ", query_no_space, strlen("SELECT SLAVE STATUS ")) == 0 + || strncasecmp("SELECT REPLICA STATUS ", query_no_space, strlen("SELECT REPLICA STATUS ")) == 0 + ) { + uint64_t addr_offset { + strstr(query_no_space, "REPLICA") ? strlen("SELECT REPLICA STATUS ") : strlen("SELECT SLAVE STATUS ") + }; if (strlen(query_no_space) > strlen("SELECT SLAVE STATUS ") + 5) { pthread_mutex_lock(&GloSQLite3Server->test_replicationlag_mutex); // the current test doesn't try to simulate failures, therefore it will return immediately @@ -879,17 +885,15 @@ __run_query: // probably never initialized GloSQLite3Server->load_replicationlag_table(sess); } - const int* rc = GloSQLite3Server->replicationlag_test_value(query_no_space + strlen("SELECT SLAVE STATUS ")); + const int* rc = GloSQLite3Server->replicationlag_test_value(query_no_space + addr_offset); free(query); - if (rc == nullptr) { - const char* a = (char*)"SELECT null as Seconds_Behind_Master"; - query = (char*)malloc(strlen(a) + 2); - sprintf(query, a); - } else { - const char* a = (char*)"SELECT %d as Seconds_Behind_Master"; - query = (char*)malloc(strlen(a) + 2); - sprintf(query, a, *rc); - } + + string SELECT { "SELECT " + (rc ? std::to_string(*rc) : string { "null" }) + " AS " }; + SELECT += strstr(query_no_space, "REPLICA") ? "Seconds_Behind_Source" : "Seconds_Behind_Master"; + + query = static_cast(malloc(SELECT.size() + 1)); + sprintf(query, SELECT.c_str()); + pthread_mutex_unlock(&GloSQLite3Server->test_replicationlag_mutex); } }