diff --git a/deps/libmicrohttpd/libmicrohttpd b/deps/libmicrohttpd/libmicrohttpd new file mode 120000 index 000000000..f4be94a80 --- /dev/null +++ b/deps/libmicrohttpd/libmicrohttpd @@ -0,0 +1 @@ +libmicrohttpd-0.9.68 \ No newline at end of file diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 10294ae74..c9adadae3 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -144,6 +144,7 @@ class MySQL_Session unsigned long long pause_until; unsigned long long idle_since; + unsigned long long transaction_started_at; // pointers MySQL_Thread *thread; @@ -171,7 +172,7 @@ class MySQL_Session int next_query_flagIN; int mirror_hostgroup; int mirror_flagOUT; - int active_transactions; + unsigned int active_transactions; int autocommit_on_hostgroup; int transaction_persistent_hostgroup; int to_process; diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index 6efef9eb2..af09a3933 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -337,6 +337,7 @@ class MySQL_Threads_Handler bool use_tcp_keepalive; int tcp_keepalive_time; int throttle_connections_per_sec_to_hostgroup; + int max_transaction_idle_time; int max_transaction_time; int threshold_query_length; int threshold_resultset_size; diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index 89e32c277..8bf20e60f 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -695,6 +695,7 @@ __thread bool mysql_thread___firewall_whitelist_enabled; __thread bool mysql_thread___use_tcp_keepalive; __thread int mysql_thread___tcp_keepalive_time; __thread int mysql_thread___throttle_connections_per_sec_to_hostgroup; +__thread int mysql_thread___max_transaction_idle_time; __thread int mysql_thread___max_transaction_time; __thread int mysql_thread___threshold_query_length; __thread int mysql_thread___threshold_resultset_size; @@ -842,6 +843,7 @@ extern __thread bool mysql_thread___firewall_whitelist_enabled; extern __thread bool mysql_thread___use_tcp_keepalive; extern __thread int mysql_thread___tcp_keepalive_time; extern __thread int mysql_thread___throttle_connections_per_sec_to_hostgroup; +extern __thread int mysql_thread___max_transaction_idle_time; extern __thread int mysql_thread___max_transaction_time; extern __thread int mysql_thread___threshold_query_length; extern __thread int mysql_thread___threshold_resultset_size; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 411dd7c5c..b7d18c41b 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -457,6 +457,8 @@ MySQL_Session::MySQL_Session() { mirrorPkt.ptr=NULL; mirrorPkt.size=0; set_status(NONE); + idle_since = 0; + transaction_started_at = 0; CurrentQuery.sess=this; @@ -2785,8 +2787,11 @@ int MySQL_Session::handler() { unsigned int j; unsigned char c; - if (active_transactions <= 0) { + if (active_transactions == 0) { active_transactions=NumActiveTransactions(); + if (active_transactions > 0) { + transaction_started_at = thread->curtime; + } } // FIXME: Sessions without frontend are an ugly hack if (session_fast_forward==false) { diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 1e78e6c51..b2ef9d1a2 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -414,6 +414,7 @@ static char * mysql_thread_variables_names[]= { (char *)"firewall_whitelist_enabled", (char *)"firewall_whitelist_errormsg", (char *)"throttle_connections_per_sec_to_hostgroup", + (char *)"max_transaction_idle_time", (char *)"max_transaction_time", (char *)"multiplexing", (char *)"log_unhealthy_connections", @@ -561,6 +562,7 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() { variables.use_tcp_keepalive=false; variables.tcp_keepalive_time=0; variables.throttle_connections_per_sec_to_hostgroup=1000000; + variables.max_transaction_idle_time=4*3600*1000; variables.max_transaction_time=4*3600*1000; variables.hostgroup_manager_verbose=1; variables.binlog_reader_connect_retry_msec=3000; @@ -978,6 +980,7 @@ int MySQL_Threads_Handler::get_variable_int(const char *name) { if (!strcmp(name,"max_connections")) return (int)variables.max_connections; if (!strcmp(name,"max_stmts_cache")) return (int)variables.max_stmts_cache; if (!strcmp(name,"max_stmts_per_connection")) return (int)variables.max_stmts_per_connection; + if (!strcmp(name,"max_transaction_idle_time")) return (int)variables.max_transaction_idle_time; if (!strcmp(name,"max_transaction_time")) return (int)variables.max_transaction_time; if (!strcmp(name,"min_num_servers_lantency_awareness")) return (int)variables.min_num_servers_lantency_awareness; } @@ -1386,6 +1389,10 @@ char * MySQL_Threads_Handler::get_variable(char *name) { // this is the public f sprintf(intbuf,"%d",variables.throttle_connections_per_sec_to_hostgroup); return strdup(intbuf); } + if (!strcasecmp(name,"max_transaction_idle_time")) { + sprintf(intbuf,"%d",variables.max_transaction_idle_time); + return strdup(intbuf); + } if (!strcasecmp(name,"max_transaction_time")) { sprintf(intbuf,"%d",variables.max_transaction_time); return strdup(intbuf); @@ -1936,6 +1943,15 @@ bool MySQL_Threads_Handler::set_variable(char *name, const char *value) { // thi return false; } } + if (!strcasecmp(name,"max_transaction_idle_time")) { + int intv=atoi(value); + if (intv >= 1000 && intv <= 20*24*3600*1000) { + variables.max_transaction_idle_time=intv; + return true; + } else { + return false; + } + } if (!strcasecmp(name,"max_transaction_time")) { int intv=atoi(value); if (intv >= 1000 && intv <= 20*24*3600*1000) { @@ -4335,18 +4351,54 @@ void MySQL_Thread::process_all_sessions() { if (idle_maintenance_thread==false) #endif // IDLE_THREADS { - sess->active_transactions=sess->NumActiveTransactions(); + { + unsigned long long sess_active_transactions = sess->active_transactions; + sess->active_transactions=sess->NumActiveTransactions(); + // in case we detected a new transaction just now + if (sess->active_transactions == 0) { + sess->transaction_started_at = 0; + } else { + if (sess_active_transactions == 0) { + sess->transaction_started_at = curtime; + } + } + } total_active_transactions_ += sess->active_transactions; sess->to_process=1; - if ( (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_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)mysql_thread___wait_timeout) ) { //numTrx = sess->NumActiveTransactions(); numTrx = sess->active_transactions; if (numTrx) { // the session has idle transactions, kill it - if (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_time) sess->killed=true; + if (sess_time/1000 > (unsigned long long)mysql_thread___max_transaction_idle_time) { + sess->killed=true; + if (sess->client_myds) { + proxy_warning("Killing client connection %s:%d because of (possible) transaction idle for %llums\n",sess->client_myds->addr.addr,sess->client_myds->addr.port, sess_time/1000); + } + } } else { // the session is idle, kill it - if (sess_time/1000 > (unsigned long long)mysql_thread___wait_timeout) sess->killed=true; + if (sess_time/1000 > (unsigned long long)mysql_thread___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); + } + } + } + } else { + if (sess->active_transactions > 0) { + // here is all the logic related to max_transaction_time + unsigned long long trx_started = sess->transaction_started_at; + if (trx_started > 0 && curtime > trx_started) { + unsigned long long trx_time = curtime - trx_started; + unsigned long long trx_time_ms = trx_time/1000; + if (trx_time_ms > (unsigned long long)mysql_thread___max_transaction_time) { + sess->killed=true; + if (sess->client_myds) { + proxy_warning("Killing client connection %s:%d because of (possible) transaction running for %llums\n",sess->client_myds->addr.addr,sess->client_myds->addr.port, trx_time_ms); + } + } + } } } if (servers_table_version_current != servers_table_version_previous) { // bug fix for #1085 @@ -4376,7 +4428,9 @@ void MySQL_Thread::process_all_sessions() { } #endif // IDLE_THREADS } else { - sess->active_transactions = -1; + // NOTE: we used the special value -1 to inform MySQL_Session::handler() to recompute it + // removing this logic in 2.0.15 + //sess->active_transactions = -1; } if (sess->healthy==0) { char _buf[1024]; @@ -4442,6 +4496,7 @@ void MySQL_Thread::refresh_variables() { mysql_thread___use_tcp_keepalive=(bool)GloMTH->get_variable_int((char *)"use_tcp_keepalive"); mysql_thread___tcp_keepalive_time=GloMTH->get_variable_int((char *)"tcp_keepalive_time"); mysql_thread___throttle_connections_per_sec_to_hostgroup=GloMTH->get_variable_int((char *)"throttle_connections_per_sec_to_hostgroup"); + mysql_thread___max_transaction_idle_time=GloMTH->get_variable_int((char *)"max_transaction_idle_time"); mysql_thread___max_transaction_time=GloMTH->get_variable_int((char *)"max_transaction_time"); mysql_thread___threshold_query_length=GloMTH->get_variable_int((char *)"threshold_query_length"); mysql_thread___threshold_resultset_size=GloMTH->get_variable_int((char *)"threshold_resultset_size");