Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package galera-4 for openSUSE:Factory 
checked in at 2023-05-05 15:57:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/galera-4 (Old)
 and      /work/SRC/openSUSE:Factory/.galera-4.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "galera-4"

Fri May  5 15:57:06 2023 rev:9 rq:1084718 version:26.4.14

Changes:
--------
--- /work/SRC/openSUSE:Factory/galera-4/galera-4.changes        2022-12-16 
17:50:54.375771483 +0100
+++ /work/SRC/openSUSE:Factory/.galera-4.new.1533/galera-4.changes      
2023-05-05 15:57:10.424046844 +0200
@@ -1,0 +2,20 @@
+Thu May  4 13:43:00 UTC 2023 - Marcus Rueckert <[email protected]>
+
+- Update to 26.4.14:
+  - memory leak in the gcs gcomm backend fixed (tp_ object deleted
+    in GCommConn destructor)
+  - protonet.backend option deprecated since it only supports one
+    option, asio, and the option will be removed in future release.
+    Related, protonet.version is also deprecated
+  - deprecation message for socket.ssl_compression as SSL
+    compression cannot be enabled and the option will be removed in
+    future releases
+  - library could parse incorrect parameters as long as it had a
+    "good" prefix, i.e. evs.*, so fix prevents setting of invalid
+    option values
+  - parsing of ISO8601 durations previously accepted invalid
+    values, now fixed
+  - in addition to ISO8601 format, parsing durations now supports
+    real number representation
+
+-------------------------------------------------------------------

Old:
----
  galera-4-26.4.13.tar.gz
  galera-4-26.4.13.tar.gz.asc

New:
----
  galera-4-26.4.14.tar.gz
  galera-4-26.4.14.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ galera-4.spec ++++++
--- /var/tmp/diff_new_pack.t9GWkH/_old  2023-05-05 15:57:11.996055850 +0200
+++ /var/tmp/diff_new_pack.t9GWkH/_new  2023-05-05 15:57:12.000055873 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package galera-4
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -25,7 +25,7 @@
   %define _fillupdir %{_localstatedir}/adm/fillup-templates
 %endif
 Name:           galera-4
-Version:        26.4.13
+Version:        26.4.14
 Release:        0
 Summary:        Galera: a synchronous multi-master wsrep provider (replication 
engine)
 License:        GPL-2.0-only

++++++ galera-4-26.4.13.tar.gz -> galera-4-26.4.14.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/GALERA_GIT_REVISION 
new/galera-4-26.4.14/GALERA_GIT_REVISION
--- old/galera-4-26.4.13/GALERA_GIT_REVISION    2022-11-03 11:54:19.000000000 
+0100
+++ new/galera-4-26.4.14/GALERA_GIT_REVISION    2023-02-24 09:38:50.000000000 
+0100
@@ -1 +1 @@
-0f7af311
\ No newline at end of file
+456ad404
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/GALERA_REVISION 
new/galera-4-26.4.14/GALERA_REVISION
--- old/galera-4-26.4.13/GALERA_REVISION        2022-11-03 11:54:19.000000000 
+0100
+++ new/galera-4-26.4.14/GALERA_REVISION        2023-02-24 09:38:50.000000000 
+0100
@@ -1 +1 @@
-0f7af311
\ No newline at end of file
+456ad404
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/GALERA_VERSION 
new/galera-4-26.4.14/GALERA_VERSION
--- old/galera-4-26.4.13/GALERA_VERSION 2022-11-03 11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/GALERA_VERSION 2023-02-24 09:38:48.000000000 +0100
@@ -1,4 +1,4 @@
 GALERA_VERSION_WSREP_API=26
 GALERA_VERSION_MAJOR=4
-GALERA_VERSION_MINOR=13
+GALERA_VERSION_MINOR=14
 GALERA_VERSION_EXTRA=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/SConstruct 
new/galera-4-26.4.14/SConstruct
--- old/galera-4-26.4.13/SConstruct     2022-11-03 11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/SConstruct     2023-02-24 09:38:48.000000000 +0100
@@ -163,7 +163,7 @@
 install = ARGUMENTS.get('install', None)
 version_script = int(ARGUMENTS.get('version_script', 1))
 
-GALERA_VER = ARGUMENTS.get('version', '4.13')
+GALERA_VER = ARGUMENTS.get('version', '4.14')
 GALERA_REV = ARGUMENTS.get('revno', 'XXXX')
 
 # Attempt to read from file if not given
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/debian/changelog 
new/galera-4-26.4.14/debian/changelog
--- old/galera-4-26.4.13/debian/changelog       2022-11-03 11:54:17.000000000 
+0100
+++ new/galera-4-26.4.14/debian/changelog       2023-02-24 09:38:48.000000000 
+0100
@@ -1,5 +1,5 @@
-galera-4 (26.4.13) UNRELEASED; urgency=medium
+galera-4 (26.4.14) UNRELEASED; urgency=medium
 
   * Galera 4 release
 
- -- Codership Oy <[email protected]>  Mon, 04 Jul 2022 14:56:52 +0300
+ -- Codership Oy <[email protected]>  Thu, 26 Jan 2023 09:31:00 +0200
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/CMakeLists.txt 
new/galera-4-26.4.14/galera/src/CMakeLists.txt
--- old/galera-4-26.4.13/galera/src/CMakeLists.txt      2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/CMakeLists.txt      2023-02-24 
09:38:48.000000000 +0100
@@ -26,7 +26,6 @@
   replicator_smm.cpp
   replicator_str.cpp
   replicator_smm_stats.cpp
-  event_service.cpp
   )
 
 target_include_directories(galera
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/SConscript 
new/galera-4-26.4.14/galera/src/SConscript
--- old/galera-4-26.4.13/galera/src/SConscript  2022-11-03 11:54:17.000000000 
+0100
+++ new/galera-4-26.4.14/galera/src/SConscript  2023-02-24 09:38:48.000000000 
+0100
@@ -33,7 +33,6 @@
     'ist.cpp',
     'gcs_dummy.cpp',
     'saved_state.cpp',
-    'event_service.cpp',
     'galera_view.cpp'
 ]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/event_service.cpp 
new/galera-4-26.4.14/galera/src/event_service.cpp
--- old/galera-4-26.4.13/galera/src/event_service.cpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/event_service.cpp   1970-01-01 
01:00:00.000000000 +0100
@@ -1,48 +0,0 @@
-//
-// Copyright (C) 2021 Codership Oy <[email protected]>
-//
-
-#include "event_service.hpp"
-
-#include <cassert>
-
-//
-// Event service hooks.
-//
-
-namespace galera
-{
-    std::mutex EventService::mutex;
-    size_t     EventService::usage(0);
-
-    EventService* EventService::instance = nullptr;
-
-    int EventService::init_v1(const wsrep_event_service_v1_t* es)
-    {
-        std::lock_guard<std::mutex> lock(EventService::mutex);
-        ++EventService::usage;
-
-        if (EventService::instance)
-        {
-            assert(0);
-            return 0;
-        }
-
-        EventService::instance = new EventService(es->context, es->event_cb);
-        return 0;
-    }
-
-    void EventService::deinit_v1()
-    {
-        std::lock_guard<std::mutex> lock(EventService::mutex);
-        assert(EventService::usage > 0);
-        --EventService::usage;
-
-        if (EventService::usage == 0)
-        {
-            delete EventService::instance;
-            EventService::instance = 0;
-        }
-    }
-
-} /* galera*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/event_service.hpp 
new/galera-4-26.4.14/galera/src/event_service.hpp
--- old/galera-4-26.4.13/galera/src/event_service.hpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/event_service.hpp   1970-01-01 
01:00:00.000000000 +0100
@@ -1,54 +0,0 @@
-//
-// Copyright (C) 2021 Codership Oy <[email protected]>
-//
-
-/**
- * Event service class
- */
-
-#ifndef GALERA_EVENT_SERVICE_HPP
-#define GALERA_EVENT_SERVICE_HPP
-
-#include "wsrep_event_service.h"
-
-#include <string>
-#include <mutex>
-
-namespace galera
-{
-    class EventService
-    {
-    public:
-        static int  init_v1(const wsrep_event_service_v1_t*);
-        static void deinit_v1();
-
-        static void callback(const std::string& name, const std::string& value)
-        {
-            std::lock_guard<std::mutex> lock(EventService::mutex);
-
-            if (instance && instance->cb_)
-            {
-                instance->cb_(instance->ctx_, name.c_str(), value.c_str());
-            }
-        }
-
-    private:
-        wsrep_event_context_t* const ctx_;
-        wsrep_event_cb_t       const cb_;
-
-        static std::mutex    mutex;
-        static size_t        usage;
-        static EventService* instance;
-
-        EventService(wsrep_event_context_t* ctx, wsrep_event_cb_t cb)
-            : ctx_(ctx), cb_(cb)
-        {}
-        virtual ~EventService() {}
-
-        EventService(const EventService&);
-        EventService& operator =(EventService);
-    };
-
-} /* galera */
-
-#endif /* GALERA_EVENT_SERVICE_HPP */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/progress_callback.hpp 
new/galera-4-26.4.14/galera/src/progress_callback.hpp
--- old/galera-4-26.4.13/galera/src/progress_callback.hpp       2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/progress_callback.hpp       2023-02-24 
09:38:48.000000000 +0100
@@ -6,7 +6,7 @@
 #define GALERA_PROGRESS_CALLBACK_HPP
 
 #include "gu_progress.hpp" // gu::Progress::Callback
-#include "event_service.hpp"
+#include "gu_event_service.hpp"
 #include "wsrep_api.h"
 
 #include <string>
@@ -34,7 +34,7 @@
                << ", \"done\": "  << done
                << ", \"undefined\": -1 }";
 
-            EventService::callback(event_name, os.str());
+            gu::EventService::callback(event_name, os.str());
         }
 
     private:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galera/src/replicator_smm_params.cpp 
new/galera-4-26.4.14/galera/src/replicator_smm_params.cpp
--- old/galera-4-26.4.13/galera/src/replicator_smm_params.cpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/replicator_smm_params.cpp   2023-02-24 
09:38:48.000000000 +0100
@@ -60,6 +60,7 @@
             conf.add(i->first, i->second);
     }
 
+    conf.set_flags(Param::causal_read_timeout, 
gu::Config::Flag::type_duration);
     conf.set_flags(Param::max_write_set_size, gu::Config::Flag::type_integer);
     conf.set_flags(Param::base_dir, gu::Config::Flag::read_only);
     conf.set_flags(Param::base_port, gu::Config::Flag::read_only |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/src/wsrep_provider.cpp 
new/galera-4-26.4.14/galera/src/wsrep_provider.cpp
--- old/galera-4-26.4.13/galera/src/wsrep_provider.cpp  2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/src/wsrep_provider.cpp  2023-02-24 
09:38:48.000000000 +0100
@@ -14,7 +14,7 @@
 #endif
 
 #include "wsrep_params.hpp"
-#include "event_service.hpp"
+#include "gu_event_service.hpp"
 #include "wsrep_config_service.h"
 
 #include <cassert>
@@ -1656,12 +1656,12 @@
 extern "C"
 int wsrep_init_event_service_v1(wsrep_event_service_v1_t *event_service)
 {
-    return galera::EventService::init_v1(event_service);
+    return gu::EventService::init_v1(event_service);
 }
 
 extern "C" void wsrep_deinit_event_service_v1()
 {
-    galera::EventService::deinit_v1();
+    gu::EventService::deinit_v1();
 }
 
 static int map_parameter_flags(int flags)
@@ -1677,6 +1677,8 @@
       ret |= WSREP_PARAM_TYPE_INTEGER;
     if (flags & gu::Config::Flag::type_double)
       ret |= WSREP_PARAM_TYPE_DOUBLE;
+    if (flags & gu::Config::Flag::type_duration)
+      ret |= WSREP_PARAM_TYPE_DOUBLE;
     return ret;
 }
 
@@ -1702,6 +1704,21 @@
     case gu::Config::Flag::type_double:
         ret = gu_str2dbl(param.value().c_str(), &wsrep_param.value.as_double);
         break;
+    case gu::Config::Flag::type_duration:
+    {
+        try
+        {
+            // durations are mapped to doubles
+            wsrep_param.value.as_double
+                = to_double(gu::datetime::Period(param.value()));
+        }
+        catch (...)
+        {
+            assert(0);
+            return 1;
+        }
+        break;
+    }
     default:
         assert((param.flags() & gu::Config::Flag::type_mask) == 0);
         wsrep_param.value.as_string = param.value().c_str();
@@ -1749,10 +1766,14 @@
 int wsrep_init_config_service_v1(wsrep_config_service_v1_t *config_service)
 {
     config_service->get_parameters = get_parameters;
+    // Deprecation checks will be done by application which uses
+    // the service.
+    gu::Config::disable_deprecation_check();
     return WSREP_OK;
 }
 
 extern "C"
 void wsrep_deinit_config_service_v1()
 {
+    gu::Config::enable_deprecation_check();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galera/tests/progress_check.cpp 
new/galera-4-26.4.14/galera/tests/progress_check.cpp
--- old/galera-4-26.4.13/galera/tests/progress_check.cpp        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galera/tests/progress_check.cpp        2023-02-24 
09:38:48.000000000 +0100
@@ -41,7 +41,7 @@
     wsrep_event_context_t event_context;
     wsrep_event_service_v1_t evs = { event_cb, &event_context };
 
-    galera::EventService::init_v1(&evs);
+    gu::EventService::init_v1(&evs);
 
     {
         galera::ProgressCallback<int> pcb(WSREP_MEMBER_JOINED,
@@ -59,7 +59,7 @@
         /* Dtor calls event callback for the third time */
     }
 
-    galera::EventService::deinit_v1();
+    gu::EventService::deinit_v1();
 }
 END_TEST
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/CMakeLists.txt 
new/galera-4-26.4.14/galerautils/src/CMakeLists.txt
--- old/galera-4-26.4.13/galerautils/src/CMakeLists.txt 2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/CMakeLists.txt 2023-02-24 
09:38:48.000000000 +0100
@@ -72,6 +72,7 @@
   gu_vlq.cpp
   gu_datetime.cpp
   gu_gtid.cpp
+  gu_event_service.cpp
   gu_exception.cpp
   gu_hexdump.cpp
   gu_serialize.cpp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/SConscript 
new/galera-4-26.4.14/galerautils/src/SConscript
--- old/galera-4-26.4.13/galerautils/src/SConscript     2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/SConscript     2023-02-24 
09:38:48.000000000 +0100
@@ -67,6 +67,7 @@
 libgalerautilsxx_sources = [
     'gu_vlq.cpp',
     'gu_datetime.cpp',
+    'gu_event_service.cpp',
     'gu_exception.cpp',
     'gu_serialize.cpp',
     'gu_logger.cpp',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_asio.cpp 
new/galera-4-26.4.14/galerautils/src/gu_asio.cpp
--- old/galera-4-26.4.13/galerautils/src/gu_asio.cpp    2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_asio.cpp    2023-02-24 
09:38:48.000000000 +0100
@@ -525,7 +525,8 @@
              gu::Config::Flag::type_bool);
     conf.add(gu::conf::ssl_compression,
              gu::Config::Flag::read_only |
-             gu::Config::Flag::type_bool);
+             gu::Config::Flag::type_bool |
+             gu::Config::Flag::deprecated);
     conf.add(gu::conf::ssl_key,
              gu::Config::Flag::read_only);
     conf.add(gu::conf::ssl_cert,
@@ -595,6 +596,12 @@
             log_info << "disabling SSL compression";
             sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
         }
+        else
+        {
+            log_warn << "SSL compression is not effective. The option "
+                     << conf::ssl_compression << " is deprecated and "
+                     << "will be removed in future releases.";
+        }
         conf.set(conf::ssl_compression, compression);
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_config.cpp 
new/galera-4-26.4.14/galerautils/src/gu_config.cpp
--- old/galera-4-26.4.13/galerautils/src/gu_config.cpp  2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_config.cpp  2023-02-24 
09:38:48.000000000 +0100
@@ -102,6 +102,9 @@
 
 gu::Config::Config() : params_() {}
 
+std::function<void(const std::string&, const gu::Config::Parameter&)>
+    gu::Config::deprecation_check_func_ = check_deprecated;
+
 void
 gu::Config::set_longlong (const std::string& key, long long val)
 {
@@ -156,6 +159,26 @@
     }
 }
 
+void gu::Config::enable_deprecation_check()
+{
+    deprecation_check_func_ = check_deprecated;
+}
+
+void gu::Config::disable_deprecation_check()
+{
+    deprecation_check_func_ = nullptr;
+}
+
+void gu::Config::check_deprecated(const std::string& key,
+                                  const Parameter& param)
+{
+    if (param.is_deprecated())
+    {
+        log_warn << "Parameter '" << key
+                 << "' is deprecated and will be removed in future versions";
+    }
+}
+
 char
 gu::Config::overflow_char(long long ret)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_config.hpp 
new/galera-4-26.4.14/galerautils/src/gu_config.hpp
--- old/galera-4-26.4.13/galerautils/src/gu_config.hpp  2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_config.hpp  2023-02-24 
09:38:48.000000000 +0100
@@ -18,6 +18,7 @@
 #include <map>
 
 #include <climits>
+#include <functional>
 
 namespace gu
 {
@@ -95,6 +96,10 @@
 
         if (i != params_.end())
         {
+            if (deprecation_check_func_)
+            {
+                deprecation_check_func_(i->first, i->second);
+            }
             i->second.set(value);
         }
         else
@@ -215,9 +220,10 @@
         static const int type_bool = (1 << 3);
         static const int type_integer = (1 << 4);
         static const int type_double = (1 << 5);
+        static const int type_duration = (1 << 6);
 
-        static const int type_mask =
-            Flag::type_bool | Flag::type_integer | Flag::type_double;
+        static const int type_mask = Flag::type_bool | Flag::type_integer
+                                     | Flag::type_double | Flag::type_duration;
 
         static std::string to_string(int f)
         {
@@ -234,6 +240,8 @@
                 s << "integer | ";
             if (f & Flag::type_double)
                 s << "double | ";
+            if (f & Flag::type_duration)
+                s << "duration | ";
             std::string ret(s.str());
             if (ret.length() > 3)
                 ret.erase(ret.length() - 3);
@@ -264,6 +272,11 @@
             return flags_ & Flag::hidden;
         }
 
+        bool is_deprecated() const
+        {
+            return flags_ & Flag::deprecated;
+        }
+
         void set(const std::string& value)
         {
             value_ = value;
@@ -288,8 +301,10 @@
     const_iterator begin() const { return params_.begin(); }
     const_iterator end()   const { return params_.end();   }
 
-private:
+    static void enable_deprecation_check();
+    static void disable_deprecation_check();
 
+private:
     static void
     key_check (const std::string& key);
 
@@ -297,6 +312,8 @@
     check_conversion (const char* ptr, const char* endptr, const char* type,
                       bool range_error = false);
 
+    static void check_deprecated(const std::string& str, const Parameter& 
param);
+
     static char
     overflow_char(long long ret);
 
@@ -309,8 +326,10 @@
     void set_longlong (const std::string& key, long long value);
 
     param_map_t params_;
-};
 
+    static std::function<void(const std::string&, const Parameter&)>
+        deprecation_check_func_;
+};
 
 extern "C" const char* gu_str2dbl  (const char* str, double* dbl);
 extern "C" const char* gu_str2bool (const char* str, bool*   bl);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_datetime.cpp 
new/galera-4-26.4.14/galerautils/src/gu_datetime.cpp
--- old/galera-4-26.4.13/galerautils/src/gu_datetime.cpp        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_datetime.cpp        2023-02-24 
09:38:48.000000000 +0100
@@ -7,10 +7,197 @@
 #include "gu_datetime.hpp"
 #include "gu_logger.hpp"
 #include "gu_utils.hpp"
+#include "gu_throw.hpp"
+#include "gu_regex.hpp"
 
-extern "C"
+#include <functional>
+
+namespace
 {
-#include "gu_time.h"
+    /*
+     * Parser for real numbers without loss of precision. Returns long long.
+     */
+
+    /* Regular expression for reals. Allowed formats:
+     * 1
+     * 1.1
+     * .1
+     */
+    const char* real_regex_str = "^([0-9]*)?\\.?([0-9]*)?$";
+    enum RealParts
+    {
+        integer = 1,
+        decimal = 2
+    };
+    constexpr size_t num_real_parts = 3;
+    gu::RegEx real_regex(real_regex_str);
+
+    /* Helper to compute powers of 10 without floating point arithmetic.
+     * The exponents must be integer in range [0, 9). */
+    long long pow_10(int exponent)
+    {
+        if (exponent < 0 || exponent >= 9)
+        {
+            throw gu::NotFound();
+        }
+        long long result = 1;
+        while (exponent != 0)
+        {
+            result *= 10;
+            --exponent;
+        }
+        return result;
+    }
+
+    /* Real number representation with integer and decimal parts
+       separated. Decimal part is represented in nanounits. */
+    struct Real
+    {
+        long long integer{0}; // Integer part
+        long long decimal{0}; // Decimal part in nanounits
+    };
+
+    /* Parse real number frrom string. */
+    Real real_from_string(const std::string& str) try
+    {
+        Real ret;
+        std::vector<gu::RegEx::Match> parts(
+            real_regex.match(str, num_real_parts));
+        if (parts.size() != 3)
+        {
+            throw gu::NotFound();
+        }
+        if (parts[RealParts::integer].is_set())
+        {
+            const auto& str = parts[RealParts::integer].str();
+            if (str.size())
+            {
+                ret.integer = std::stoll(str);
+            }
+        }
+        if (parts[RealParts::decimal].is_set())
+        {
+            const auto& str = parts[RealParts::decimal].str();
+            if (str.size())
+            {
+                const auto n_decis = str.size();
+                if (n_decis > 9)
+                {
+                    throw gu::NotFound();
+                }
+                const int exponent = 9 - n_decis;
+                const long long multiplier = pow_10(exponent);
+                ret.decimal = std::stoll(str) * multiplier;
+            }
+        }
+        return ret;
+    }
+    catch (...)
+    {
+        throw gu::NotFound();
+    }
+
+    /* Parse seconds from string, return long long. */
+    long long seconds_from_string(const std::string& str)
+    {
+        auto real = real_from_string(str);
+        const auto max = std::numeric_limits<long long>::max();
+        if (max/gu::datetime::Sec < real.integer)
+        {
+            /* Multiplication would overflow */
+            throw gu::NotFound();
+        }
+        if (real.integer * gu::datetime::Sec > max - real.decimal)
+        {
+            /* Addition would overflow */
+            throw gu::NotFound();
+        }
+        return real.integer * gu::datetime::Sec + real.decimal;
+    }
+
+    /* Parse seconds from string with multiplier. It is assumed that the
+     * str argument contains integer. */
+    template <long long Mult>
+    long long seconds_from_string_mult(const std::string& str) try
+    {
+        const auto val = std::stoll(str);
+        const auto max = std::numeric_limits<long long>::max();
+        if (max/Mult < val)
+        {
+            /* Multiplication would overflow */
+            throw gu::NotFound();
+        }
+        return (val * Mult);
+    }
+    catch(...)
+    {
+        throw gu::NotFound();
+    }
+
+    const char* const period_regex =
+      "^(P)(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?"
+/*      1  23          45          67                             */
+      "((T)?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+(\\.?[0-9]*))?S)?)?$";
+/*     89    11          13          15                           */
+
+  gu::RegEx regex(period_regex);
+
+  enum
+  {
+      GU_P     = 1,
+      GU_YEAR  = 3,
+      GU_MONTH = 5,
+      GU_DAY   = 7,
+      GU_HOUR  = 10,
+      GU_MIN   = 12,
+      GU_SEC   = 15,
+      GU_NUM_PARTS = 17
+  };
+
+  struct regex_group
+  {
+      int index;
+      std::function<long long(const std::string& str)> parse;
+  };
+
+  const struct regex_group regex_groups[]
+  {
+      { GU_YEAR, seconds_from_string_mult<gu::datetime::Year> },
+      { GU_MONTH, seconds_from_string_mult<gu::datetime::Month> },
+      { GU_DAY, seconds_from_string_mult<gu::datetime::Day> },
+      { GU_HOUR, seconds_from_string_mult<gu::datetime::Hour> },
+      { GU_MIN, seconds_from_string_mult<gu::datetime::Min> },
+      { GU_SEC, seconds_from_string },
+  };
+
+  long long iso8601_duration_to_nsecs(const std::string& str)
+  {
+      long long nsecs = 0;
+      std::vector<gu::RegEx::Match> parts;
+      try
+      {
+          parts = regex.match(str, GU_NUM_PARTS);
+      }
+      catch (...) {
+          throw gu::NotFound();
+      }
+
+      for (auto g : regex_groups)
+      {
+          if (parts[g.index].is_set())
+          {
+              const long long val(g.parse(parts[g.index].str()));
+              const long long max(std::numeric_limits<long long>::max());
+              if (nsecs > max - val)
+              {
+                  // addition would overflow
+                  throw gu::NotFound();
+              }
+              nsecs += val;
+          }
+      }
+      return nsecs;
+  }
 }
 
 long long gu::datetime::SimClock::counter_(0);
@@ -49,79 +236,15 @@
     gu_throw_fatal << "not implemented";
 }
 
-const char* const gu::datetime::Period::period_regex =
-         "^(P)(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?"
-/*         1  23          45          67                             */
-         "((T)?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+)(\\.([0-9]+))?S)?)?";
-/*        89    11          13          15      16                   */
-
-enum
-{
-    GU_P     = 1,
-    GU_YEAR  = 3,
-    GU_MONTH = 5,
-    GU_DAY   = 7,
-    GU_HOUR  = 10,
-    GU_MIN   = 12,
-    GU_SEC   = 15,
-    GU_SEC_D = 16,
-    GU_NUM_PARTS = 17
-};
-
-gu::RegEx const gu::datetime::Period::regex(period_regex);
 
 void gu::datetime::Period::parse(const std::string& str)
 {
-    std::vector<RegEx::Match> parts = regex.match(str, GU_NUM_PARTS);
-
-    if (parts[GU_P].is_set() == false)
-    {
-        if (str == "")
-        {
-            return;
-        }
-        else
-        {
-            gu_throw_error (EINVAL) << "Period " << str << " not valid";
-        }
-    }
-
-    if (parts[GU_YEAR].is_set())
-    {
-        nsecs += from_string<long long>(parts[GU_YEAR].str())*Year;
-    }
-
-    if (parts[GU_MONTH].is_set())
-    {
-        nsecs += from_string<long long>(parts[GU_MONTH].str())*Month;
-    }
-
-    if (parts[GU_DAY].is_set())
-    {
-        nsecs += from_string<long long>(parts[GU_DAY].str())*Day;
-    }
-
-    if (parts[GU_HOUR].is_set())
-    {
-        nsecs += from_string<long long>(parts[GU_HOUR].str())*Hour;
-    }
-
-    if (parts[GU_MIN].is_set())
-    {
-        nsecs += from_string<long long>(parts[GU_MIN].str())*Min;
-    }
-
-    if (parts[GU_SEC].is_set())
+    try
     {
-        long long s(from_string<long long>(parts[GU_SEC].str()));
-        nsecs += s*Sec;
+        nsecs = ::iso8601_duration_to_nsecs(str);
     }
-
-    if (parts[GU_SEC_D].is_set())
+    catch (...)
     {
-        double d(from_string<double>(parts[GU_SEC_D].str()));
-        nsecs += static_cast<long long>(d*Sec);
+        nsecs = seconds_from_string(str);
     }
 }
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_datetime.hpp 
new/galera-4-26.4.14/galerautils/src/gu_datetime.hpp
--- old/galera-4-26.4.13/galerautils/src/gu_datetime.hpp        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_datetime.hpp        2023-02-24 
09:38:48.000000000 +0100
@@ -11,10 +11,9 @@
 
 
 #include "gu_exception.hpp"
-#include "gu_regex.hpp"
 #include "gu_time.h"
 
-#include <iostream>
+#include <sstream>
 #include <string>
 #include <limits>
 
@@ -41,16 +40,24 @@
         {
         public:
             /*!
-             * @brief Constructor
+             * @brief Construct gu::datetime::Period from string
              *
-             * Duration format is PnYnMnDTnHnMnS where Y is year, M is month,
-             * D is day, T is the time designator separating date and time
-             * parts, H denotes hours, M (after T) is minutes and S seconds.
+             * This constructor accepts a string that contains a duration
+             * represented in ISO8601 format. Alternatively, it accepts a
+             * string that represents a double duration in number of seconds.
+             *
+             * The ISO8601 duration format is PnYnMnDTnHnMnS where Y is year,
+             * M is month, D is day, T is the time designator separating date
+             * and time parts, H denotes hours, M (after T) is minutes and S
+             * seconds.
              *
              * All other n:s are expected to be integers except the one
              * before S which can be decimal to represent fractions of second.
              *
-             * @param str Time period represented in ISO8601 duration format.
+             * @param str Time period represented in ISO8601 duration format,
+             *            or number of seconds represented as double.
+             *
+             * @throws NotFound
              */
             Period(const std::string& str = "") :
                 nsecs()
@@ -97,9 +104,6 @@
             friend class Date;
             friend std::istream& operator>>(std::istream&, Period&);
 
-            static const char* const period_regex; /*! regexp string */
-            static RegEx       const regex;        /*! period string parser */
-
             /*!
              * @brief Parse period string.
              */
@@ -237,6 +241,11 @@
             return os.str();
         }
 
+        inline double to_double(const Period& p)
+        {
+            return static_cast<double>(p.get_nsecs()) / Sec;
+        }
+
         inline std::istream& operator>>(std::istream& is, Period& p)
         {
             std::string str;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galerautils/src/gu_event_service.cpp 
new/galera-4-26.4.14/galerautils/src/gu_event_service.cpp
--- old/galera-4-26.4.13/galerautils/src/gu_event_service.cpp   1970-01-01 
01:00:00.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_event_service.cpp   2023-02-24 
09:38:48.000000000 +0100
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 Codership Oy <[email protected]>
+//
+
+#include "gu_event_service.hpp"
+
+#include <cassert>
+
+//
+// Event service hooks.
+//
+
+namespace gu
+{
+    std::mutex EventService::mutex;
+    size_t     EventService::usage(0);
+
+    EventService* EventService::instance = nullptr;
+
+    int EventService::init_v1(const wsrep_event_service_v1_t* es)
+    {
+        std::lock_guard<std::mutex> lock(EventService::mutex);
+        ++EventService::usage;
+
+        if (EventService::instance)
+        {
+            assert(0);
+            return 0;
+        }
+
+        EventService::instance = new EventService(es->context, es->event_cb);
+        return 0;
+    }
+
+    void EventService::deinit_v1()
+    {
+        std::lock_guard<std::mutex> lock(EventService::mutex);
+        assert(EventService::usage > 0);
+        --EventService::usage;
+
+        if (EventService::usage == 0)
+        {
+            delete EventService::instance;
+            EventService::instance = 0;
+        }
+    }
+
+} /* galera*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galerautils/src/gu_event_service.hpp 
new/galera-4-26.4.14/galerautils/src/gu_event_service.hpp
--- old/galera-4-26.4.13/galerautils/src/gu_event_service.hpp   1970-01-01 
01:00:00.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_event_service.hpp   2023-02-24 
09:38:48.000000000 +0100
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 Codership Oy <[email protected]>
+//
+
+/**
+ * Event service class
+ */
+
+#ifndef GALERA_EVENT_SERVICE_HPP
+#define GALERA_EVENT_SERVICE_HPP
+
+#include "wsrep_event_service.h"
+
+#include <string>
+#include <mutex>
+
+namespace gu
+{
+    class EventService
+    {
+    public:
+        static int  init_v1(const wsrep_event_service_v1_t*);
+        static void deinit_v1();
+
+        static void callback(const std::string& name, const std::string& value)
+        {
+            std::lock_guard<std::mutex> lock(EventService::mutex);
+
+            if (instance && instance->cb_)
+            {
+                instance->cb_(instance->ctx_, name.c_str(), value.c_str());
+            }
+        }
+
+    private:
+        wsrep_event_context_t* const ctx_;
+        wsrep_event_cb_t       const cb_;
+
+        static std::mutex    mutex;
+        static size_t        usage;
+        static EventService* instance;
+
+        EventService(wsrep_event_context_t* ctx, wsrep_event_cb_t cb)
+            : ctx_(ctx), cb_(cb)
+        {}
+        ~EventService() {}
+
+        EventService(const EventService&);
+        EventService& operator =(EventService);
+    };
+
+} /* galera */
+
+#endif /* GALERA_EVENT_SERVICE_HPP */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/src/gu_utils.hpp 
new/galera-4-26.4.14/galerautils/src/gu_utils.hpp
--- old/galera-4-26.4.13/galerautils/src/gu_utils.hpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/src/gu_utils.hpp   2023-02-24 
09:38:48.000000000 +0100
@@ -66,7 +66,11 @@
 
     try
     {
-        if ((iss >> f >> ret).fail()) throw NotFound();
+        iss >> f >> ret;
+        if (iss.fail() || not iss.eof())
+        {
+            throw NotFound();
+        }
     }
     catch (gu::Exception& e)
     {
@@ -93,7 +97,11 @@
     std::istringstream iss(s);
     void*              ret;
 
-    if ((iss >> std::hex >> ret).fail()) throw NotFound();
+    iss >> std::hex >> ret;
+    if (iss.fail() || not iss.eof())
+    {
+        throw NotFound();
+    }
 
     return ret;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/tests/CMakeLists.txt 
new/galera-4-26.4.14/galerautils/tests/CMakeLists.txt
--- old/galera-4-26.4.13/galerautils/tests/CMakeLists.txt       2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/CMakeLists.txt       2023-02-24 
09:38:48.000000000 +0100
@@ -58,6 +58,7 @@
   gu_mem_pool_test.cpp
   gu_alloc_test.cpp
   gu_rset_test.cpp
+  gu_utils_test++.cpp
   gu_string_utils_test.cpp
   gu_uri_test.cpp
   gu_config_test.cpp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/tests/SConscript 
new/galera-4-26.4.14/galerautils/tests/SConscript
--- old/galera-4-26.4.13/galerautils/tests/SConscript   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/SConscript   2023-02-24 
09:38:48.000000000 +0100
@@ -74,6 +74,7 @@
                               gu_asio_test.cpp
                               gu_deqmap_test.cpp
                               gu_progress_test.cpp
+                              gu_utils_test++.cpp
                               gu_tests++.cpp
                            '''))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galerautils/tests/gu_datetime_test.cpp 
new/galera-4-26.4.14/galerautils/tests/gu_datetime_test.cpp
--- old/galera-4-26.4.13/galerautils/tests/gu_datetime_test.cpp 2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/gu_datetime_test.cpp 2023-02-24 
09:38:48.000000000 +0100
@@ -5,10 +5,9 @@
 #include "gu_datetime.hpp"
 #include "gu_logger.hpp"
 #include "gu_utils.hpp"
-
 #include "gu_datetime_test.hpp"
 
-
+#include <cmath> // std::fabs
 
 using namespace gu;
 using namespace gu::datetime;
@@ -53,22 +52,78 @@
     ck_assert(Period("P5Y66DT").get_nsecs() == 5*Year + 66*Day);
     ck_assert(Period("P37M44DT").get_nsecs() == 37*Month + 44*Day);
 
-
     // Hour-min-sec
     ck_assert(Period("PT3H").get_nsecs() == 3*Hour);
     ck_assert(Period("PT5M").get_nsecs() == 5*Min);
     ck_assert(Period("P37S").get_nsecs() == 37*Sec);
 
-    // ck_assert(Period("PT3.578777S").get_nsecs() == 3*Sec + 578*MSec + 
777*USec);
+    // Decimal seconds
     ck_assert(Period("PT0.5S").get_nsecs() == 500*MSec);
+    ck_assert(Period("PT3.578777S").get_nsecs() == 3*Sec + 578*MSec + 
777*USec);
+    ck_assert(Period("PT5H7M3.578777S").get_nsecs()
+              == 5*Hour + 7*Min + 3*Sec + 578*MSec + 777*USec);
+
+    // Full
+    ck_assert(Period("P10Y5M4DT3H24M1.1S").get_nsecs()
+              == 10*Year + 5*Month + 4*Day + 3*Hour + 24*Min + 1.1*Sec);
+}
+END_TEST
 
+static void assert_invalid_period(const std::string& period)
+{
+    bool exception = false;
+    try
+    {
+        Period p(period);
+    }
+    catch (gu::NotFound& exp)
+    {
+        exception = true;
+    }
+    ck_assert(exception);
+}
 
-    // ck_assert(Period("PT5H7M3.578777S").get_nsecs() == 5*Hour + 7*Min + 
3*Sec + 578*MSec + 777*USec);    
-    
-    // @todo these should fail
-    ck_assert(Period("PT.S").get_nsecs() == 0);
-    ck_assert(Period("PT.D").get_nsecs() == 0);
+START_TEST(test_period_invalid)
+{
+    assert_invalid_period("a");
+    assert_invalid_period("anyvalue");
+    assert_invalid_period("Panyvalue");
+    assert_invalid_period("PT.S");
+    assert_invalid_period("PT.D");
+    assert_invalid_period("PT1D");
+    assert_invalid_period("P1D1Y");
+    assert_invalid_period("P9223372036854775807Y"); // Overflow
+}
+END_TEST
 
+static void assert_double_eq_tol(double left, double right, double tol)
+{
+    ck_assert(std::fabs(left - right) < tol);
+}
+
+START_TEST(test_period_from_double)
+{
+    ck_assert(Period("0").get_nsecs() == 0);
+    ck_assert(Period(".1").get_nsecs() ==  100*MSec);
+    ck_assert(Period("0.0").get_nsecs() == 0);
+    ck_assert(Period("0.5").get_nsecs() == 500*MSec);
+    // Use microsecond precision for comparison to make
+    // it work on x86
+    assert_double_eq_tol(to_double(Period("0.5")), 0.5,  0.000001);
+    assert_double_eq_tol(to_double(Period(".111111111")), 0.111111111,
+                         0.000001);;
+}
+END_TEST
+
+START_TEST(test_period_overflow)
+{
+    long long max_secs = std::numeric_limits<long long>::max() / 
gu::datetime::Sec;
+
+    std::string max_duration("PT" + std::to_string(max_secs) + "S");
+    ck_assert(Period(max_duration).get_nsecs()); // no overflow
+
+    std::string overflow_duration("PT" + std::to_string(max_secs + 1.0) + "S");
+    assert_invalid_period(overflow_duration);
 }
 END_TEST
 
@@ -112,6 +167,18 @@
     tcase_add_test(tc, test_period);
     suite_add_tcase(s, tc);
 
+    tc = tcase_create("test_period_invalid");
+    tcase_add_test(tc, test_period_invalid);
+    suite_add_tcase(s, tc);
+
+    tc = tcase_create("test_period_from_double");
+    tcase_add_test(tc, test_period_from_double);
+    suite_add_tcase(s, tc);
+
+    tc = tcase_create("test_period_overflow");
+    tcase_add_test(tc, test_period_overflow);
+    suite_add_tcase(s, tc);
+
     tc = tcase_create("test_date");
     tcase_add_test(tc, test_date);
     suite_add_tcase(s, tc);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/galerautils/tests/gu_tests++.hpp 
new/galera-4-26.4.14/galerautils/tests/gu_tests++.hpp
--- old/galera-4-26.4.13/galerautils/tests/gu_tests++.hpp       2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/gu_tests++.hpp       2023-02-24 
09:38:48.000000000 +0100
@@ -29,6 +29,7 @@
 #include "gu_thread_test.hpp"
 #include "gu_asio_test.hpp"
 #include "gu_deqmap_test.hpp"
+#include "gu_utils_test++.hpp"
 
 typedef Suite *(*suite_creator_t)(void);
 
@@ -53,6 +54,7 @@
     gu_thread_suite,
     gu_asio_suite,
     gu_deqmap_suite,
+    gu_utils_cpp_suite,
     0
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galerautils/tests/gu_utils_test++.cpp 
new/galera-4-26.4.14/galerautils/tests/gu_utils_test++.cpp
--- old/galera-4-26.4.13/galerautils/tests/gu_utils_test++.cpp  1970-01-01 
01:00:00.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/gu_utils_test++.cpp  2023-02-24 
09:38:48.000000000 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009-2020 Codership Oy <[email protected]>
+ */
+
+#include "gu_utils.hpp"
+#include "gu_utils_test++.hpp"
+
+static void assert_invalid_int(const std::string& test_str,
+                               std::ios_base& (*f)(std::ios_base&) = std::dec)
+{
+    bool exception(false);
+    try
+    {
+        gu::from_string<int>(test_str);
+    }
+    catch (gu::NotFound)
+    {
+        exception = true;
+    }
+    ck_assert(exception);
+}
+
+START_TEST(test_from_string_invalid_int)
+{
+    // used to parse '1'
+    assert_invalid_int("1dummy");
+    assert_invalid_int("1 dummy");
+    assert_invalid_int("0x1whatever", std::hex);
+
+    // used to parse 'd'
+    assert_invalid_int("dummy", std::hex);
+}
+END_TEST
+
+
+static void assert_invalid_bool(const std::string& test_str)
+{
+    bool exception(false);
+    try
+    {
+        gu::from_string<bool>(test_str);
+    }
+    catch (gu::NotFound)
+    {
+        exception = true;
+    }
+    ck_assert(exception);
+}
+
+START_TEST(test_from_string_invalid_bool)
+{
+    assert_invalid_bool("true 1");
+}
+END_TEST
+
+
+Suite* gu_utils_cpp_suite()
+{
+    Suite* s = suite_create("gu::utils");
+    TCase* tc;
+
+    tc = tcase_create("test_from_string_invalid_int");
+    tcase_add_test(tc, test_from_string_invalid_int);
+    suite_add_tcase(s, tc);
+
+    tc = tcase_create("test_from_string_invalid_bool");
+    tcase_add_test(tc, test_from_string_invalid_bool);
+    suite_add_tcase(s, tc);
+
+    return s;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/galerautils/tests/gu_utils_test++.hpp 
new/galera-4-26.4.14/galerautils/tests/gu_utils_test++.hpp
--- old/galera-4-26.4.13/galerautils/tests/gu_utils_test++.hpp  1970-01-01 
01:00:00.000000000 +0100
+++ new/galera-4-26.4.14/galerautils/tests/gu_utils_test++.hpp  2023-02-24 
09:38:48.000000000 +0100
@@ -0,0 +1,10 @@
+// Copyright (C) 2022 Codership Oy <[email protected]>
+
+#ifndef __gu_utils_test_hpp__
+#define __gu_utils_test_hpp__
+
+#include <check.h>
+
+Suite* gu_utils_cpp_suite();
+
+#endif /* __gu_utils_test_hpp__ */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/src/defaults.cpp 
new/galera-4-26.4.14/gcomm/src/defaults.cpp
--- old/galera-4-26.4.13/gcomm/src/defaults.cpp 2022-11-03 11:54:17.000000000 
+0100
+++ new/galera-4-26.4.14/gcomm/src/defaults.cpp 2023-02-24 09:38:48.000000000 
+0100
@@ -9,12 +9,7 @@
 
 namespace gcomm
 {
-#ifdef HAVE_ASIO_HPP
     std::string const Defaults::ProtonetBackend         = "asio";
-#else
-#error "Only asio protonet backend is currently supported"
-#endif /* HAVE_ASIO_HPP */
-
     std::string const Defaults::ProtonetVersion         = "0";
     std::string const Defaults::SocketChecksum          = "2";
     std::string const Defaults::SocketRecvBufSize       =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/src/defaults.hpp 
new/galera-4-26.4.14/gcomm/src/defaults.hpp
--- old/galera-4-26.4.13/gcomm/src/defaults.hpp 2022-11-03 11:54:17.000000000 
+0100
+++ new/galera-4-26.4.14/gcomm/src/defaults.hpp 2023-02-24 09:38:48.000000000 
+0100
@@ -61,8 +61,10 @@
         static const int BasePort = gu::Config::Flag::read_only |
                                     gu::Config::Flag::type_integer;
 
-        static const int ProtonetBackend = gu::Config::Flag::read_only;
-        static const int ProtonetVersion = gu::Config::Flag::read_only;
+        static const int ProtonetBackend
+            = gu::Config::Flag::read_only | gu::Config::Flag::deprecated;
+        static const int ProtonetVersion
+            = gu::Config::Flag::read_only | gu::Config::Flag::deprecated;
 
         // Hidden because not documented / does not seem to be used?
         static const int TcpNonBlocking = gu::Config::Flag::hidden;
@@ -81,8 +83,10 @@
                                              gu::Config::Flag::type_integer;
         static const int GMCastMCastTTL    = gu::Config::Flag::read_only |
                                              gu::Config::Flag::type_integer;
-        static const int GMCastTimeWait    = gu::Config::Flag::read_only;
-        static const int GMCastPeerTimeout = gu::Config::Flag::read_only;
+        static const int GMCastTimeWait    = gu::Config::Flag::read_only |
+                                             gu::Config::Flag::type_duration;
+        static const int GMCastPeerTimeout = gu::Config::Flag::read_only |
+                                             gu::Config::Flag::type_duration;;
         // Hidden because undocumented
         static const int GMCastMaxInitialReconnectAttempts =
             gu::Config::Flag::hidden | gu::Config::Flag::type_integer;
@@ -94,23 +98,24 @@
                                              gu::Config::Flag::type_integer;
 
         static const int EvsVersion           = gu::Config::Flag::read_only;
-        static const int EvsViewForgetTimeout = gu::Config::Flag::read_only;
-        static const int EvsSuspectTimeout    = 0;
-        static const int EvsInactiveTimeout   = 0;
-        static const int EvsInactiveCheckPeriod = 0;
-        static const int EvsInstallTimeout    = 0;
-        static const int EvsKeepalivePeriod   = 0;
-        static const int EvsJoinRetransPeriod = 0;
-        static const int EvsStatsReportPeriod = 0;
+        static const int EvsViewForgetTimeout = gu::Config::Flag::read_only |
+                                                
gu::Config::Flag::type_duration;
+        static const int EvsSuspectTimeout    = 
gu::Config::Flag::type_duration;
+        static const int EvsInactiveTimeout   = 
gu::Config::Flag::type_duration;
+        static const int EvsInactiveCheckPeriod = 
gu::Config::Flag::type_duration;
+        static const int EvsInstallTimeout    = 
gu::Config::Flag::type_duration;
+        static const int EvsKeepalivePeriod   = 
gu::Config::Flag::type_duration;
+        static const int EvsJoinRetransPeriod = 
gu::Config::Flag::type_duration;
+        static const int EvsStatsReportPeriod = 
gu::Config::Flag::type_duration;
         static const int EvsDebugLogMask      = 0;
         static const int EvsInfoLogMask       = 0;
         static const int EvsSendWindow        = gu::Config::Flag::type_integer;
         static const int EvsUserSendWindow    = gu::Config::Flag::type_integer;
         static const int EvsUseAggregate      = gu::Config::Flag::type_bool;
-        static const int EvsCausalKeepalivePeriod = 0;
+        static const int EvsCausalKeepalivePeriod = 
gu::Config::Flag::type_duration;
         static const int EvsMaxInstallTimeouts = 
gu::Config::Flag::type_integer;
-        static const int EvsDelayMargin       = 0;
-        static const int EvsDelayedKeepPeriod = 0;
+        static const int EvsDelayMargin       = 
gu::Config::Flag::type_duration;
+        static const int EvsDelayedKeepPeriod = 
gu::Config::Flag::type_duration;
         static const int EvsEvict             = 0;
         static const int EvsAutoEvict         = gu::Config::Flag::read_only |
                                                 gu::Config::Flag::type_bool;
@@ -119,13 +124,16 @@
         static const int PcIgnoreSb           = gu::Config::Flag::type_bool;
         static const int PcIgnoreQuorum       = gu::Config::Flag::type_bool;
         static const int PcChecksum           = gu::Config::Flag::type_bool;
-        static const int PcAnnounceTimeout    = gu::Config::Flag::read_only;
-        static const int PcLinger             = gu::Config::Flag::read_only;
+        static const int PcAnnounceTimeout    = gu::Config::Flag::read_only |
+                                                
gu::Config::Flag::type_duration;
+        static const int PcLinger             = gu::Config::Flag::read_only |
+                                                
gu::Config::Flag::type_duration;
         static const int PcNpvo               = gu::Config::Flag::type_bool;
         static const int PcBootstrap          = gu::Config::Flag::type_bool;
         static const int PcWaitPrim           = gu::Config::Flag::read_only |
                                                 gu::Config::Flag::type_bool;
-        static const int PcWaitPrimTimeout    = gu::Config::Flag::read_only;
+        static const int PcWaitPrimTimeout    = gu::Config::Flag::read_only |
+                                                
gu::Config::Flag::type_duration;
         static const int PcWeight             = gu::Config::Flag::type_integer;
         static const int PcRecovery           = gu::Config::Flag::read_only |
                                                 gu::Config::Flag::type_bool;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/src/evs_proto.cpp 
new/galera-4-26.4.14/gcomm/src/evs_proto.cpp
--- old/galera-4-26.4.13/gcomm/src/evs_proto.cpp        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcomm/src/evs_proto.cpp        2023-02-24 
09:38:48.000000000 +0100
@@ -19,6 +19,7 @@
 #include <numeric>
 #include <iterator>
 #include <set>
+#include <iostream> // std::cerr
 
 using namespace std::rel_ops;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/src/gmcast_proto.cpp 
new/galera-4-26.4.14/gcomm/src/gmcast_proto.cpp
--- old/galera-4-26.4.13/gcomm/src/gmcast_proto.cpp     2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcomm/src/gmcast_proto.cpp     2023-02-24 
09:38:48.000000000 +0100
@@ -6,6 +6,17 @@
 #include "gmcast.hpp"
 
 #include "gu_uri.hpp"
+#include "gu_event_service.hpp"
+
+static void emit_evicted_event()
+{
+    std::ostringstream os;
+    os << "{\"status\": \"evicted\", "
+       << "\"message\": "
+       << "\"This node was evicted permanently from cluster, "
+       << "restart is required\"}";
+    gu::EventService::callback("event", os.str());
+}
 
 static const std::string gmcast_proto_err_evicted("evicted");
 static const std::string gmcast_proto_err_invalid_group("invalid group");
@@ -280,6 +291,7 @@
         // otherwise node use the uuid in view state file.
         // which is probably still in other nodes evict list.
         gmcast_.remove_viewstate_file();
+        emit_evicted_event();
         gu_throw_fatal
             << "this node has been evicted out of the cluster, "
             << "gcomm backend restart is required";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/src/pc_proto.cpp 
new/galera-4-26.4.14/gcomm/src/pc_proto.cpp
--- old/galera-4-26.4.13/gcomm/src/pc_proto.cpp 2022-11-03 11:54:17.000000000 
+0100
+++ new/galera-4-26.4.14/gcomm/src/pc_proto.cpp 2023-02-24 09:38:48.000000000 
+0100
@@ -12,6 +12,7 @@
 #include "gu_macros.h"
 #include <algorithm>
 #include <set>
+#include <iostream> // std::cerr
 
 #include <boost/bind.hpp>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/test/check_trace.cpp 
new/galera-4-26.4.14/gcomm/test/check_trace.cpp
--- old/galera-4-26.4.13/gcomm/test/check_trace.cpp     2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcomm/test/check_trace.cpp     2023-02-24 
09:38:48.000000000 +0100
@@ -11,6 +11,7 @@
 #include "check_trace.hpp"
 #include "gcomm/conf.hpp"
 #include "gu_asio.hpp" // gu::ssl_register_params()
+#include <iostream> // std::cerr
 
 using namespace std;
 using namespace gu;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/gcomm/test/ssl_test.cpp 
new/galera-4-26.4.14/gcomm/test/ssl_test.cpp
--- old/galera-4-26.4.13/gcomm/test/ssl_test.cpp        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcomm/test/ssl_test.cpp        2023-02-24 
09:38:48.000000000 +0100
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <stdexcept>
+#include <iostream> // std::cerr
 
 static gu::Config conf;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/gcs/src/unit_tests/gcs_core_test.cpp 
new/galera-4-26.4.14/gcs/src/unit_tests/gcs_core_test.cpp
--- old/galera-4-26.4.13/gcs/src/unit_tests/gcs_core_test.cpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcs/src/unit_tests/gcs_core_test.cpp   2023-02-24 
09:38:48.000000000 +0100
@@ -550,14 +550,18 @@
 
 // do a single send step, compare with the expected result
 static inline bool
-CORE_SEND_STEP (gcs_core_t* core, long timeout, long ret)
+CORE_SEND_STEP (gcs_core_t* core, long timeout, long ret, int line)
 {
    long err = gcs_core_send_step (core, timeout);
    ck_assert_msg(err >= 0, "gcs_core_send_step(): %ld (%s)",
                  err, strerror (-err));
    if (ret >= 0) {
-       ck_assert_msg(err == ret, "gcs_core_send_step(): expected %ld, got %ld",
-                     ret, err);
+       if (err != ret) {
+           fprintf(stderr, "gcs_core_send_step(%ld, %ld) at line %d:"
+                   " expected %ld, got %ld", timeout, ret, line, ret, err);
+           assert(0); // to catch a core if possible
+           ck_abort();
+       }
    }
 
    return false;
@@ -625,11 +629,11 @@
 
     ck_assert(!CORE_RECV_START (&act_r));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     usleep (10000); // resolve race between sending and setting transitional
     gcs_dummy_set_transitional (Backend);
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
-    ck_assert(!CORE_SEND_STEP (Core, tout, 0)); // no frags left
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 0, __LINE__)); // no frags left
     ck_assert(NULL == act_r.out); // should not have received anything
     ck_assert(!gcs_dummy_set_component (Backend, prim)); // return to PRIM 
state
     ck_assert(!CORE_SEND_END (&act_s, act_size));
@@ -643,8 +647,8 @@
      */
     ck_assert(!DUMMY_INJECT_COMPONENT (Backend, non_prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
     ck_assert(!CORE_SEND_END (&act_s, act_size));
     ck_assert(!gcs_dummy_set_component(Backend, non_prim));
     ck_assert(!CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CCHANGE));
@@ -662,8 +666,8 @@
      * fragment send fails.
      */
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
-    ck_assert(!CORE_SEND_STEP (Core, tout, 0)); // bail out after 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 0, __LINE__)); // bail out after 
1st frag
     ck_assert(!CORE_SEND_END (&act_s, -ENOTCONN));
 
     /*
@@ -676,7 +680,7 @@
     ck_assert(!gcs_dummy_set_component(Backend, non_prim));
     ck_assert(!DUMMY_INJECT_COMPONENT (Backend, non_prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     ck_assert(!CORE_SEND_END (&act_s, -ENOTCONN));
     ck_assert(!CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CCHANGE));
     ck_assert(!core_test_check_conf(act_r.out, act_r.size, false, 0, 1));
@@ -690,9 +694,9 @@
      */
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     ck_assert(!DUMMY_INJECT_COMPONENT (Backend, non_prim));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
     ck_assert(!CORE_SEND_END (&act_s, act_size));
     ck_assert(!CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CCHANGE));
     ck_assert(!core_test_check_conf(act_r.out, act_r.size, false, 0, 1));
@@ -710,11 +714,11 @@
      */
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     usleep (100000); // make sure 1st fragment gets in before new component
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, non_prim));
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, prim));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
     ck_assert(!CORE_SEND_END (&act_s, act_size));
     ck_assert(!CORE_RECV_ACT (&act_r, act_buf, act_size, GCS_ACT_WRITESET));
     ck_assert_msg(-ERESTART == act_r.seqno,
@@ -739,26 +743,26 @@
     // subcase 1
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     ck_assert(!DUMMY_INJECT_COMPONENT (Backend, non_prim));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
     usleep (500000); // fail_if_seq
     ck_assert(!gcs_dummy_set_component(Backend, non_prim));
     ck_assert(!CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CCHANGE));
     ck_assert(!core_test_check_conf(act_r.out, act_r.size, false, 0, 1));
     Cache->free(act_r.out);
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 3rd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 3rd frag
     ck_assert(!CORE_SEND_END (&act_s, -ENOTCONN));
 
     // subcase 2
     ck_assert(!DUMMY_INSTALL_COMPONENT (Backend, prim));
     ck_assert(!CORE_SEND_START (&act_s));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 1st frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 1st frag
     ck_assert(!DUMMY_INJECT_COMPONENT (Backend, non_prim));
-    ck_assert(!CORE_SEND_STEP (Core, tout, 1)); // 2nd frag
+    ck_assert(!CORE_SEND_STEP (Core, tout, 1, __LINE__)); // 2nd frag
     usleep (1000000);
     ck_assert(!gcs_dummy_set_component(Backend, non_prim));
-    ck_assert(!CORE_SEND_STEP (Core, 4*tout, 1)); // 3rd frag
+    ck_assert(!CORE_SEND_STEP (Core, 4*tout, 1, __LINE__)); // 3rd frag
     ck_assert(!CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CCHANGE));
     ck_assert(!core_test_check_conf(act_r.out, act_r.size, false, 0, 1));
     Cache->free(act_r.out);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/gcs/src/unit_tests/gcs_memb_test.cpp 
new/galera-4-26.4.14/gcs/src/unit_tests/gcs_memb_test.cpp
--- old/galera-4-26.4.13/gcs/src/unit_tests/gcs_memb_test.cpp   2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/gcs/src/unit_tests/gcs_memb_test.cpp   2023-02-24 
09:38:48.000000000 +0100
@@ -116,7 +116,9 @@
     Suite *suite = suite_create("GCS membership changes");
     TCase *tcase = tcase_create("gcs_memb");
 
-    suite_add_tcase (suite, tcase);
-    tcase_add_test  (tcase, gcs_memb_test_465);
+    suite_add_tcase  (suite, tcase);
+    tcase_add_test   (tcase, gcs_memb_test_465);
+    tcase_set_timeout(tcase, 30);
+
     return suite;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/galera-4-26.4.13/scripts/packages/codership-galera.spec 
new/galera-4-26.4.14/scripts/packages/codership-galera.spec
--- old/galera-4-26.4.13/scripts/packages/codership-galera.spec 2022-11-03 
11:54:20.000000000 +0100
+++ new/galera-4-26.4.14/scripts/packages/codership-galera.spec 2023-02-24 
09:38:51.000000000 +0100
@@ -21,7 +21,7 @@
 
 %define name galera-4
 %define wsrep_api 26
-%{!?version: %define version 26.4.13}
+%{!?version: %define version 26.4.14}
 %{!?release: %define release 1}
 %define copyright Copyright 2007-2020 Codership Oy. All rights reserved. Use 
is subject to license terms under GPLv2 license.
 %define libs %{_libdir}/%{name}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galera-4-26.4.13/tests/scripts/action.sh 
new/galera-4-26.4.14/tests/scripts/action.sh
--- old/galera-4-26.4.13/tests/scripts/action.sh        2022-11-03 
11:54:17.000000000 +0100
+++ new/galera-4-26.4.14/tests/scripts/action.sh        2023-02-24 
09:38:48.000000000 +0100
@@ -1,11 +1,23 @@
 # Helper to get status variable value
 
+mysql_command()
+{
+    local node=$1
+    if [ "${NODE_LOCATION[$node]}" = "local" ]
+    then
+        echo "${NODE_TEST_DIR[$node]}/mysql/bin/mysql"
+    else
+        echo "mysql"
+    fi
+}
+
 cluster_status()
 {
     local node=$1
     case "$DBMS" in
         "MYSQL")
-            local res=$(mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \
+            local command=$(mysql_command $node)
+            local res=$($command -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \
                 -h${NODE_INCOMING_HOST[$node]} -P${NODE_INCOMING_PORT[$node]} \
                 --skip-column-names -ss \
                 -e "SET wsrep_on=0;
@@ -22,7 +34,9 @@
 {
     local node=$1
     local query=$2
-    mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \
+    local command=$(mysql_command $node)
+
+    $command -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \
           -h${NODE_INCOMING_HOST[$node]} -P${NODE_INCOMING_PORT[$node]} \
           --skip-column-names -ss -e "$query"
 }

Reply via email to