From d559459f982c803de606e638f8ff897f4928fbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Thu, 13 Jul 2017 20:33:29 +0200 Subject: [PATCH] Bug fix for #1085 Immediatelly kill all client connections using an OFFLINE node --- include/MySQL_Session.h | 1 + include/MySQL_Thread.h | 2 ++ include/mysql_connection.h | 1 + lib/MySQL_Session.cpp | 17 +++++++++++++++++ lib/MySQL_Thread.cpp | 12 ++++++++++++ lib/mysql_connection.cpp | 16 ++++++++++++++++ 6 files changed, 49 insertions(+) diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 9f4f5ed49c..4972f3209f 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -195,6 +195,7 @@ class MySQL_Session void MySQL_Result_to_MySQL_wire(MYSQL *mysql, MySQL_ResultSet *MyRS, MySQL_Data_Stream *_myds=NULL); void MySQL_Stmt_Result_to_MySQL_wire(MYSQL_STMT *stmt, MySQL_Connection *myconn); unsigned int NumActiveTransactions(); + bool HasOfflineBackends(); int FindOneActiveTransaction(); unsigned long long IdleTime(); diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index 3daef4e309..f589776109 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -155,6 +155,8 @@ class ProxySQL_Poll { class MySQL_Thread { private: + unsigned int servers_table_version_previous; + unsigned int servers_table_version_current; unsigned long long last_processing_idles; MySQL_Connection **my_idle_conns; bool processing_idles; diff --git a/include/mysql_connection.h b/include/mysql_connection.h index 56d2db4bd4..7ba984dc69 100644 --- a/include/mysql_connection.h +++ b/include/mysql_connection.h @@ -165,6 +165,7 @@ class MySQL_Connection { } return ret; } + bool IsServerOffline(); bool IsAutoCommit(); bool MultiplexDisabled(); void ProcessQueryAndSetStatusFlags(char *query_digest_text); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index e8f28c2467..3bd874c564 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -3755,6 +3755,23 @@ unsigned int MySQL_Session::NumActiveTransactions() { return ret; } +bool MySQL_Session::HasOfflineBackends() { + bool ret=false; + if (mybes==0) return ret; + MySQL_Backend *_mybe; + unsigned int i; + for (i=0; i < mybes->len; i++) { + _mybe=(MySQL_Backend *)mybes->index(i); + if (_mybe->server_myds) + if (_mybe->server_myds->myconn) + if (_mybe->server_myds->myconn->IsServerOffline()) { + ret=true; + return ret; + } + } + return ret; +} + int MySQL_Session::FindOneActiveTransaction() { int ret=-1; if (mybes==0) return ret; diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 8b783d624d..e544f5f268 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -2474,6 +2474,8 @@ void MySQL_Thread::run() { if (curtime > last_maintenance_time + maintenance_interval) { last_maintenance_time=curtime; maintenance_loop=true; + servers_table_version_previous = servers_table_version_current; + servers_table_version_current = MyHGM->get_servers_table_version(); } else { maintenance_loop=false; } @@ -2907,6 +2909,12 @@ void MySQL_Thread::process_all_sessions() { if (sess_time/1000 > (unsigned long long)mysql_thread___wait_timeout) sess->killed=true; } } + if (servers_table_version_current != servers_table_version_previous) { // bug fix for #1085 + // Immediatelly kill all client connections using an OFFLINE node + if (sess->HasOfflineBackends()) { + sess->killed=true; + } + } } #ifdef IDLE_THREADS else @@ -3104,6 +3112,10 @@ MySQL_Thread::MySQL_Thread() { status_variables.frontend_stmt_prepare=0; status_variables.frontend_stmt_execute=0; status_variables.frontend_stmt_close=0; + + servers_table_version_previous=0; + servers_table_version_current=0; + status_variables.queries=0; status_variables.queries_slow=0; status_variables.queries_backends_bytes_sent=0; diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index b5f1218268..5b65180233 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -1125,6 +1125,22 @@ int MySQL_Connection::async_connect(short event) { } +bool MySQL_Connection::IsServerOffline() { + bool ret=false; + if (parent==NULL) + return ret; + server_status=parent->status; // we copy it here to avoid race condition. The caller will see this + if ( + (server_status==MYSQL_SERVER_STATUS_OFFLINE_HARD) // the server is OFFLINE as specific by the user + || + (server_status==MYSQL_SERVER_STATUS_SHUNNED && parent->shunned_automatic==true && parent->shunned_and_kill_all_connections==true) // the server is SHUNNED due to a serious issue + || + (server_status==MYSQL_SERVER_STATUS_SHUNNED_REPLICATION_LAG) // slave is lagging! see #774 + ) { + ret=true; + } + return ret; +} // Returns: // 0 when the query is completed