From e1ad625fca0e03631a79864c33282f3888b6f9e8 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 15 Jul 2015 20:47:49 +0000 Subject: [PATCH] improved and now optional Galera cluster health check --- phpgwapi/inc/class.egw_db.inc.php | 42 ++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/phpgwapi/inc/class.egw_db.inc.php b/phpgwapi/inc/class.egw_db.inc.php index 4b9a9058a2..ea1adb40bf 100644 --- a/phpgwapi/inc/class.egw_db.inc.php +++ b/phpgwapi/inc/class.egw_db.inc.php @@ -170,6 +170,13 @@ class egw_db */ static $tablealiases = array(); + /** + * Callback to check if selected node is healty / should be used + * + * @var callback throwing egw_exception_db_connection, if connected node should NOT be used + */ + static $health_check; + /** * db allows sub-queries, true for everything but mysql < 4.1 * @@ -349,13 +356,10 @@ class egw_db //error_log(__METHOD__."() this->Host(s)=$this->Host, n=$n --> host=$host"); $new_connection = !$this->Link_ID || !$this->Link_ID->IsConnected(); $this->_connect($host); - // check Galera wsrep_local_state for node is not in state Synced, eg. Donor - // check is only done for Type=mysql and will succed if no Galera - if ($new_connection && $this->Type == 'mysql' && strpos($this->Host, ';') !== false && - ($state = $this->query("SHOW STATUS LIKE 'wsrep_local_state'")->fetchColumn(1)) !== false && - $state != 4) // 4 = Synced + // check if connected node is healty + if ($new_connection && self::$health_check) { - throw new egw_exception_db_connection('wsrep-local-state='.array2string($state).' != 4'); + call_user_func(self::$health_check, $this); } //error_log(__METHOD__."() host=$host, new_connection=$new_connection, this->Type=$this->Type, this->Host=$this->Host, wsrep_local_state=".array2string($state)); return $this->Link_ID; @@ -370,6 +374,32 @@ class egw_db throw $e; } + /** + * Check if just connected Galera cluster node is healthy / fully operational + * + * A node in state "Donor/Desynced" will block updates at the end of a SST. + * Therefore we try to avoid that node, if we have an alternative. + * + * To enable this check add the following to your header.inc.php: + * + * egw_db::$health_check = array('egw_db', 'galera_cluster_health'); + * + * @param egw_db $db already connected egw_db instance to check + * @throws egw_exception_db_connection if node should NOT be used + */ + static function galera_cluster_health(egw_db $db) + { + if (($state = $db->query("SHOW STATUS WHERE Variable_name in ('wsrep_cluster_size','wsrep_local_state','wsrep_local_state_comment')")->GetAssoc())) + { + if ($state['wsrep_local_state_comment'] == 'Synced' || + // if we have only 2 nodes (2. one starting), we can only use the donor + $state['wsrep_local_state_comment'] == 'Donor/Desynced' && + $state['wsrep_cluster_size'] == 2) return; + + throw new egw_exception_db_connection('Node is NOT Synced! '.array2string($state)); + } + } + /** * Get one of multiple (semicolon-separated) DB-hosts to use *