From abe16e6692b2cb0538bbbc376bf36ba64d126bdf Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Wed, 2 Apr 2025 13:47:06 +0530 Subject: [PATCH 1/3] Parsing and setting wait timeout for session --- include/Base_Session.h | 1 + lib/MySQL_Session.cpp | 17 +++++++++++++++++ lib/MySQL_Thread.cpp | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/Base_Session.h b/include/Base_Session.h index 5c35a86f8..9c763cf16 100644 --- a/include/Base_Session.h +++ b/include/Base_Session.h @@ -82,6 +82,7 @@ class Base_Session { int pending_connect; enum proxysql_session_type session_type; int warning_in_hg; + int wait_timeout; //in milliseconds // bool bool autocommit; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 888cb05de..23fa4a446 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -681,6 +681,7 @@ MySQL_Session::MySQL_Session() { last_HG_affected_rows = -1; // #1421 : advanced support for LAST_INSERT_ID() proxysql_node_address = NULL; use_ldap_auth = false; + wait_timeout = mysql_thread___wait_timeout; } /** @@ -6414,6 +6415,22 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection charset to %d\n", c->nr); client_myds->myconn->set_charset(c->nr, NAMES); } + } else if (var == "wait_timeout") { + std::string value = *values++; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Client requested SET wait_timeout = %s\n", value.c_str()); + + int client_timeout = atoi(value.c_str()) * 1000; // converting into milliseconds, mysql set timeout is in second + + if (client_timeout <= 0 || client_timeout > mysql_thread___wait_timeout) { + char errmsg[128]; + snprintf(errmsg, sizeof(errmsg), "wait_timeout is less/equal than 0 or wait_timeout is %d exceeds maximum allowed %d", client_timeout, mysql_thread___wait_timeout); + client_myds->DSS = STATE_QUERY_SENT_NET; + client_myds->myprot.generate_pkt_ERR(true, NULL, NULL, 1, 1231, (char *)"42000", errmsg, true); + client_myds->DSS = STATE_SLEEP; + status = WAITING_CLIENT_DATA; + return true; + } + wait_timeout = client_timeout; } else if (var == "tx_isolation") { std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET tx_isolation value %s\n", value1.c_str()); diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 834569625..3a7585ffa 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -3790,7 +3790,7 @@ void MySQL_Thread::ProcessAllSessions_MaintenanceLoop(MySQL_Session *sess, unsig * @param curtime The current time, in milliseconds. * @param sess The MySQL session to handle. */ - if ( (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_idle_time) || (sess_time/1000 > (unsigned long long)mysql_thread___wait_timeout) ) { + if ( (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_idle_time) || (sess_time/1000 > (unsigned long long)sess->wait_timeout) ) { //numTrx = sess->NumActiveTransactions(); numTrx = sess->active_transactions; if (numTrx) { @@ -3803,7 +3803,7 @@ void MySQL_Thread::ProcessAllSessions_MaintenanceLoop(MySQL_Session *sess, unsig } } else { // the session is idle, kill it - if (sess_time/1000 > (unsigned long long)mysql_thread___wait_timeout) { + if (sess_time/1000 > (unsigned long long)sess->wait_timeout) { sess->killed=true; if (sess->client_myds) { proxy_warning("Killing client connection %s:%d because inactive for %llums\n",sess->client_myds->addr.addr,sess->client_myds->addr.port, sess_time/1000); From d7ec497afd8df29f2234b61d543fd8c4a8f1a30c Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Fri, 4 Apr 2025 09:22:38 +0530 Subject: [PATCH 2/3] Now taking effective timeout taking as minimum of global timeout and session timeout --- include/Base_Session.h | 2 +- lib/MySQL_Session.cpp | 44 ++++++++++++++++++++++++++++++++++++------ lib/MySQL_Thread.cpp | 7 ++++++- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/include/Base_Session.h b/include/Base_Session.h index 9c763cf16..8e68a176b 100644 --- a/include/Base_Session.h +++ b/include/Base_Session.h @@ -82,7 +82,7 @@ class Base_Session { int pending_connect; enum proxysql_session_type session_type; int warning_in_hg; - int wait_timeout; //in milliseconds + unsigned long long wait_timeout; //in milliseconds // bool bool autocommit; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 23fa4a446..25a2fa7d6 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -6416,21 +6416,53 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C client_myds->myconn->set_charset(c->nr, NAMES); } } else if (var == "wait_timeout") { + // MySQL min allowed value, 1 second in milliseconds + const unsigned long long MYSQL_WAIT_TIMEOUT_MIN_MS = 1 * 1000; + // MySQL max allowed value, 365 days in milliseconds + const unsigned long long MYSQL_WAIT_TIMEOUT_MAX_MS = 31536000ULL * 1000; + std::string value = *values++; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Client requested SET wait_timeout = %s\n", value.c_str()); - - int client_timeout = atoi(value.c_str()) * 1000; // converting into milliseconds, mysql set timeout is in second - - if (client_timeout <= 0 || client_timeout > mysql_thread___wait_timeout) { + + unsigned long long client_timeout = 0; + try { + client_timeout = std::stoull(value) * 1000; + } catch (const std::exception& e) { char errmsg[128]; - snprintf(errmsg, sizeof(errmsg), "wait_timeout is less/equal than 0 or wait_timeout is %d exceeds maximum allowed %d", client_timeout, mysql_thread___wait_timeout); + snprintf(errmsg, sizeof(errmsg), + "Incorrect argument type wait_timeout value: %s", value.c_str()); + client_myds->DSS = STATE_QUERY_SENT_NET; + client_myds->myprot.generate_pkt_ERR(true, nullptr, nullptr, 1, 1231, (char *)"42000", errmsg, true); + client_myds->DSS = STATE_SLEEP; + status = WAITING_CLIENT_DATA; + return true; + } + + auto is_within_range = [](unsigned long long val, unsigned long long min, unsigned long long max) { + return val >= min && val <= max; + }; + + // Enforcing min/max MySQL wait_timeout range + if (!is_within_range(client_timeout, MYSQL_WAIT_TIMEOUT_MIN_MS, MYSQL_WAIT_TIMEOUT_MAX_MS)) { + char errmsg[256]; + snprintf(errmsg, sizeof(errmsg), + "wait_timeout must be between %llu ms (1s) and %llu ms (365d), received: %llu ms", + MYSQL_WAIT_TIMEOUT_MIN_MS, MYSQL_WAIT_TIMEOUT_MAX_MS, client_timeout); client_myds->DSS = STATE_QUERY_SENT_NET; - client_myds->myprot.generate_pkt_ERR(true, NULL, NULL, 1, 1231, (char *)"42000", errmsg, true); + client_myds->myprot.generate_pkt_ERR(true, nullptr, nullptr, 1, 1231, (char *)"42000", errmsg, true); client_myds->DSS = STATE_SLEEP; status = WAITING_CLIENT_DATA; return true; } + + // Warn if client's value exceeds current global timeout + if (client_timeout > mysql_thread___wait_timeout) { + proxy_error("[Warning] Client-specified wait_timeout (%llu ms) exceeds global mysql-wait_timeout (%llu ms). Global timeout will still be enforced.", + client_timeout, mysql_thread___wait_timeout); + } + wait_timeout = client_timeout; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection wait_timeout to %llu ms\n", client_timeout); } else if (var == "tx_isolation") { std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET tx_isolation value %s\n", value1.c_str()); diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 3a7585ffa..514c68249 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -3790,7 +3790,12 @@ void MySQL_Thread::ProcessAllSessions_MaintenanceLoop(MySQL_Session *sess, unsig * @param curtime The current time, in milliseconds. * @param sess The MySQL session to handle. */ - if ( (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_idle_time) || (sess_time/1000 > (unsigned long long)sess->wait_timeout) ) { + unsigned long long effective_wait_timeout = std::min( + static_cast(mysql_thread___wait_timeout), + static_cast(sess->wait_timeout) + ); + if ((sess_time/1000 > static_cast(mysql_thread___max_transaction_idle_time)) || + (sess_time/1000 > effective_wait_timeout)) { //numTrx = sess->NumActiveTransactions(); numTrx = sess->active_transactions; if (numTrx) { From 1545fd244c9619fee69e06d69b675d8d0241728f Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Fri, 4 Apr 2025 17:48:58 +0530 Subject: [PATCH 3/3] Removed range check. --- lib/MySQL_Session.cpp | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 25a2fa7d6..76c5ae8ff 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -6416,11 +6416,6 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C client_myds->myconn->set_charset(c->nr, NAMES); } } else if (var == "wait_timeout") { - // MySQL min allowed value, 1 second in milliseconds - const unsigned long long MYSQL_WAIT_TIMEOUT_MIN_MS = 1 * 1000; - // MySQL max allowed value, 365 days in milliseconds - const unsigned long long MYSQL_WAIT_TIMEOUT_MAX_MS = 31536000ULL * 1000; - std::string value = *values++; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Client requested SET wait_timeout = %s\n", value.c_str()); @@ -6438,31 +6433,19 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C return true; } - auto is_within_range = [](unsigned long long val, unsigned long long min, unsigned long long max) { - return val >= min && val <= max; - }; - - // Enforcing min/max MySQL wait_timeout range - if (!is_within_range(client_timeout, MYSQL_WAIT_TIMEOUT_MIN_MS, MYSQL_WAIT_TIMEOUT_MAX_MS)) { - char errmsg[256]; - snprintf(errmsg, sizeof(errmsg), - "wait_timeout must be between %llu ms (1s) and %llu ms (365d), received: %llu ms", - MYSQL_WAIT_TIMEOUT_MIN_MS, MYSQL_WAIT_TIMEOUT_MAX_MS, client_timeout); - client_myds->DSS = STATE_QUERY_SENT_NET; - client_myds->myprot.generate_pkt_ERR(true, nullptr, nullptr, 1, 1231, (char *)"42000", errmsg, true); - client_myds->DSS = STATE_SLEEP; - status = WAITING_CLIENT_DATA; - return true; - } - // Warn if client's value exceeds current global timeout - if (client_timeout > mysql_thread___wait_timeout) { - proxy_error("[Warning] Client-specified wait_timeout (%llu ms) exceeds global mysql-wait_timeout (%llu ms). Global timeout will still be enforced.", - client_timeout, mysql_thread___wait_timeout); + if (client_timeout > static_cast(mysql_thread___wait_timeout)) { + proxy_warning("Client [%s] (user: %s) requested wait_timeout = %llu ms, exceeds the global mysql-wait_timeout = %d ms. Global timeout will still be enforced.", + client_myds->myconn->connected_host_details.ip, + client_myds->myconn->userinfo->username, + client_timeout, + mysql_thread___wait_timeout); + } + + if (wait_timeout != client_timeout) { + wait_timeout = client_timeout; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection wait_timeout to %llu ms\n", client_timeout); } - - wait_timeout = client_timeout; - proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection wait_timeout to %llu ms\n", client_timeout); } else if (var == "tx_isolation") { std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET tx_isolation value %s\n", value1.c_str());