]> review.fuel-infra Code Review - packages/centos7/MySQL-wsrep.git/commitdiff
MySQL-wsrep package for centos7. 13/12113/11
authorIvan Suzdal <isuzdal@mirantis.com>
Thu, 24 Sep 2015 17:42:16 +0000 (20:42 +0300)
committerIvan Suzdal <isuzdal@mirantis.com>
Mon, 28 Sep 2015 10:23:17 +0000 (13:23 +0300)
Rebuild from packages/centos6/MySQL-wsrep 7.0 branch.

Change-Id: I3b099bba87772beb1007156150e48eed586cee69
Related-Bug: #1462998

disable_tests.patch [new file with mode: 0644]
fix-man-page-links.patch [new file with mode: 0644]
fix_standalone_tests.patch [new file with mode: 0644]
mysql-5.6.23.tar.gz [new file with mode: 0644]
mysql-5.6.23_wsrep_25.10.patch [new file with mode: 0644]
mysql.spec [new file with mode: 0644]
scripts__mysqld_safe.sh__signals.patch [new file with mode: 0644]
spelling.patch [new file with mode: 0644]
wsrep_sst_mysqldump.patch [new file with mode: 0644]

diff --git a/disable_tests.patch b/disable_tests.patch
new file mode 100644 (file)
index 0000000..7dff43b
--- /dev/null
@@ -0,0 +1,7 @@
+--- a/mysql-test/t/disabled.def
++++ b/mysql-test/t/disabled.def
+@@ -17,3 +17,4 @@ log_tables-big           : Bug#11756699
+ ds_mrr-big @solaris      : Bug#14168107 2012-04-03 Hemant disabled new test added by Olav Sandstå,since this leads to timeout on Solaris on slow sparc servers
+ mysql_embedded_client_test    : Bug#13964673 2012-04-16 amitbha since most of the test cases are failing
+ mysql_client_test_embedded : Bug#16084066 2013-01-08 Disabled since this test is failing
++file_contents            : Fails without bzr revision id
diff --git a/fix-man-page-links.patch b/fix-man-page-links.patch
new file mode 100644 (file)
index 0000000..4098907
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/man/mysql_client_test_embedded.1 2013-11-08 19:00:22.000000000 +0530
++++ b/man/mysql_client_test_embedded.1 2013-11-14 19:29:56.768315219 +0530
+@@ -1 +1 @@
+-.so man/mysql_client_test.1
++.so man1/mysql_client_test.1
+--- a/man/mysqltest_embedded.1 2013-11-08 19:00:22.000000000 +0530
++++ b/man/mysqltest_embedded.1 2013-11-14 19:31:19.079280675 +0530
+@@ -1 +1 @@
+-.so man/mysqltest.1
++.so man1/mysqltest.1
diff --git a/fix_standalone_tests.patch b/fix_standalone_tests.patch
new file mode 100644 (file)
index 0000000..2ca95bf
--- /dev/null
@@ -0,0 +1,12 @@
+--- mysql-5.5.orig/mysql-test/lib/mtr_cases.pm 2011-11-14 15:35:04.238715000 -0800
++++ mysql-5.5/mysql-test/lib/mtr_cases.pm      2011-11-25 14:41:00.433887578 -0800
+@@ -287,7 +287,8 @@
+     else
+     {
+       $suitedir= my_find_dir($::basedir,
+-                           ["share/mysql-test/suite",
++                             ["lib/mysql-testsuite/suite",
++                              "share/mysql-test/suite",
+                             "mysql-test/suite",
+                             "internal/mysql-test/suite",
+                             "mysql-test",
diff --git a/mysql-5.6.23.tar.gz b/mysql-5.6.23.tar.gz
new file mode 100644 (file)
index 0000000..8b3d006
Binary files /dev/null and b/mysql-5.6.23.tar.gz differ
diff --git a/mysql-5.6.23_wsrep_25.10.patch b/mysql-5.6.23_wsrep_25.10.patch
new file mode 100644 (file)
index 0000000..39ff8b9
--- /dev/null
@@ -0,0 +1,43353 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 5be5e92..818313e 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -176,6 +176,7 @@ IF(WITH_DEFAULT_FEATURE_SET)
+ ENDIF()
+ # Add macros
++INCLUDE(wsrep)
+ INCLUDE(character_sets)
+ INCLUDE(cpu_info)
+ INCLUDE(zlib)
+@@ -324,6 +325,12 @@ OPTION(OPTIMIZER_TRACE "Support tracing of Optimizer" ON)
+ OPTION(INNODB_COMPILER_HINTS "Compile InnoDB with compiler hints" ON)
+ MARK_AS_ADVANCED(INNODB_COMPILER_HINTS)
++OPTION(WITH_INNODB_DISALLOW_WRITES "InnoDB freeze writes patch from Google" ${WITH_WSREP})
++IF (WITH_INNODB_DISALLOW_WRITES)
++  MESSAGE(STATUS "INNODB_DISALLOW_WRITES")
++  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWITH_INNODB_DISALLOW_WRITES")
++  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_INNODB_DISALLOW_WRITES")
++ENDIF()
+ OPTION(INNODB_PAGE_ATOMIC_REF_COUNT "Use atomics for the page reference count"
+        ON)
+ MARK_AS_ADVANCED(INNODB_PAGE_ATOMIC_REF_COUNT)
+@@ -444,6 +451,9 @@ ADD_SUBDIRECTORY(regex)
+ ADD_SUBDIRECTORY(mysys)
+ ADD_SUBDIRECTORY(mysys_ssl)
+ ADD_SUBDIRECTORY(libmysql)
++IF(WITH_WSREP)
++ADD_SUBDIRECTORY(wsrep)
++ENDIF()
+ IF(WITH_UNIT_TESTS)
+   ADD_SUBDIRECTORY(unittest)
+@@ -539,7 +549,7 @@ ADD_SUBDIRECTORY(packaging/solaris)
+ # (see http://public.kitware.com/Bug/view.php?id=11452)
+ SET(CPACK_MONOLITHIC_INSTALL 1 CACHE INTERNAL "")
+-IF(UNIX)
++IF(UNIX AND NOT WITH_WSREP)
+   INSTALL(FILES Docs/mysql.info DESTINATION ${INSTALL_INFODIR} OPTIONAL COMPONENT Info)
+ ENDIF()
+ #
+@@ -554,7 +564,7 @@ IF(NOT INSTALL_LAYOUT MATCHES "RPM")
+   INSTALL(FILES README DESTINATION ${INSTALL_DOCREADMEDIR} COMPONENT Readme)
+   INSTALL(FILES ${CMAKE_BINARY_DIR}/Docs/INFO_SRC ${CMAKE_BINARY_DIR}/Docs/INFO_BIN DESTINATION ${INSTALL_DOCDIR})
+   IF(UNIX)
+-    INSTALL(FILES Docs/INSTALL-BINARY DESTINATION ${INSTALL_DOCREADMEDIR} COMPONENT Readme)
++    INSTALL(FILES Docs/INSTALL-BINARY Docs/README-wsrep DESTINATION ${INSTALL_DOCREADMEDIR} COMPONENT Readme)
+   ENDIF()
+   # MYSQL_DOCS_LOCATON is used in "make dist", points to the documentation directory
+   SET(MYSQL_DOCS_LOCATION "" CACHE PATH "Location from where documentation is copied")
+@@ -562,6 +572,7 @@ IF(NOT INSTALL_LAYOUT MATCHES "RPM")
+   INSTALL(DIRECTORY Docs/ DESTINATION ${INSTALL_DOCDIR}
+     COMPONENT Documentation
+     PATTERN "INSTALL-BINARY" EXCLUDE
++    PATTERN "README-wsrep" EXCLUDE
+     PATTERN "Makefile.*" EXCLUDE
+     PATTERN "glibc*" EXCLUDE
+     PATTERN "linuxthreads.txt" EXCLUDE
+diff --git a/Docs/ChangeLog b/Docs/ChangeLog
+index 9988db3..e1775d5 100644
+--- a/Docs/ChangeLog
++++ b/Docs/ChangeLog
+@@ -1 +1,2 @@
+-This is a first release, this file is supposed to be empty
++Placeholder
++
+diff --git a/Docs/INFO_SRC b/Docs/INFO_SRC
+deleted file mode 100644
+index fbc1a6c..0000000
+--- a/Docs/INFO_SRC
++++ /dev/null
+@@ -1,7 +0,0 @@
+-commit: 19ff9770da1307a8b44be40beaa456c4d1149c2a
+-date: 2015-01-19 14:26:20 +0100
+-build-date: 2015-01-19 14:38:00 +0100
+-short: 19ff977
+-branch: mysql-5.6.23-release
+-
+-MySQL source 5.6.23
+diff --git a/WSREP_REVISION b/WSREP_REVISION
+new file mode 100644
+index 0000000..72dd598
+--- /dev/null
++++ b/WSREP_REVISION
+@@ -0,0 +1 @@
++6b378be
+diff --git a/client/mysqltest.cc b/client/mysqltest.cc
+index 2def9bd..1421309 100644
+--- a/client/mysqltest.cc
++++ b/client/mysqltest.cc
+@@ -496,7 +496,7 @@ struct st_match_err
+ struct st_expected_errors
+ {
+-  struct st_match_err err[10];
++  struct st_match_err err[20];
+   uint count;
+ };
+ static struct st_expected_errors saved_expected_errors;
+diff --git a/cmake/configure.pl b/cmake/configure.pl
+index 22c1329..0a6a3cf 100644
+--- a/cmake/configure.pl
++++ b/cmake/configure.pl
+@@ -223,6 +223,16 @@ foreach my $option (@ARGV)
+     $cmakeargs = $cmakeargs." \"-DWITH_COMMENT=".substr($option,13)."\""; 
+     next;
+   }
++  if ($option =~ /layout=/)
++  {
++    $cmakeargs = $cmakeargs." -DINSTALL_LAYOUT=".substr($option,7); 
++    next;
++  }
++  if ($option =~ /with-unix-socket-path=/)
++  {
++    $cmakeargs = $cmakeargs." -DMYSQL_UNIX_ADDR=".substr($option,22); 
++    next;
++  }
+   if ($option =~ /mysql-maintainer-mode/)
+   {
+     $cmakeargs = $cmakeargs." -DMYSQL_MAINTAINER_MODE=" .
+diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake
+index 4adda0b..5cd47af 100644
+--- a/cmake/install_layout.cmake
++++ b/cmake/install_layout.cmake
+@@ -146,7 +146,10 @@ SET(INSTALL_BINDIR_RPM                  "bin")
+ SET(INSTALL_SBINDIR_RPM                 "sbin")
+ SET(INSTALL_SCRIPTDIR_RPM               "bin")
+ #
+-IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
++# Deciding via system processor may give wrong answer in
++# virtual environments that see host CPU directly.
++# IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
++IF(64BIT)
+   SET(INSTALL_LIBDIR_RPM                "lib64")
+   SET(INSTALL_PLUGINDIR_RPM             "lib64/mysql/plugin")
+ ELSE()
+diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake
+index 83bd6bd..4f66008 100644
+--- a/cmake/install_macros.cmake
++++ b/cmake/install_macros.cmake
+@@ -13,8 +13,34 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
++if(APPLE)
++ LIST(APPEND CMAKE_CXX_LINK_EXECUTABLE "dsymutil <TARGET>")
++ LIST(APPEND CMAKE_C_LINK_EXECUTABLE "dsymutil <TARGET>")
++ LIST(APPEND CMAKE_CXX_CREATE_SHARED_LIBRARY "dsymutil <TARGET>")
++ LIST(APPEND CMAKE_C_CREATE_SHARED_LIBRARY "dsymutil <TARGET>")
++ LIST(APPEND CMAKE_CXX_CREATE_SHARED_MODULE "dsymutil <TARGET>")
++ LIST(APPEND CMAKE_C_CREATE_SHARED_MODULE "dsymutil <TARGET>")
++ENDIF()
++
+ GET_FILENAME_COMPONENT(MYSQL_CMAKE_SCRIPT_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+ INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/cmake_parse_arguments.cmake)
++MACRO (INSTALL_DSYM_DIRECTORIES targets)
++  IF(APPLE)
++    FOREACH(target ${targets})
++      GET_TARGET_PROPERTY(location ${target} LOCATION)
++      GET_TARGET_PROPERTY(type ${target} TYPE)
++      # It's a dirty hack, but cmake too stupid and mysql cmake files too buggy */
++      STRING(REGEX REPLACE "/liblibmysql.dylib$" "/libmysqlclient.${SHARED_LIB_MAJOR_VERSION}.dylib" location ${location})
++      IF(DEBUG_EXTNAME)
++        STRING(REGEX REPLACE "/mysqld$" "/mysqld-debug" location ${location})
++      ENDIF()
++      IF(type MATCHES "EXECUTABLE" OR type MATCHES "MODULE" OR type MATCHES "SHARED_LIBRARY")
++        INSTALL(DIRECTORY "${location}.dSYM" DESTINATION ${INSTALL_LOCATION} COMPONENT Debuginfo)
++      ENDIF()
++    ENDFOREACH()
++  ENDIF()
++ENDMACRO()
++
+ MACRO (INSTALL_DEBUG_SYMBOLS targets)
+   IF(MSVC)
+   FOREACH(target ${targets})
+@@ -241,6 +267,7 @@ FUNCTION(MYSQL_INSTALL_TARGETS)
+   INSTALL(TARGETS ${TARGETS} DESTINATION ${ARG_DESTINATION} ${COMP})
+   SET(INSTALL_LOCATION ${ARG_DESTINATION} )
+   INSTALL_DEBUG_SYMBOLS("${TARGETS}")
++  INSTALL_DSYM_DIRECTORIES("${TARGETS}")
+   SET(INSTALL_LOCATION)
+ ENDFUNCTION()
+diff --git a/cmake/os/FreeBSD.cmake b/cmake/os/FreeBSD.cmake
+index e095929..bd72a58 100644
+--- a/cmake/os/FreeBSD.cmake
++++ b/cmake/os/FreeBSD.cmake
+@@ -22,3 +22,5 @@
+ # The below was used for really old versions of FreeBSD, roughly: before 5.1.9
+ # ADD_DEFINITIONS(-DHAVE_BROKEN_REALPATH)
++
++SET(HAVE_SYS_TIMEB_H CACHE  INTERNAL "")
+diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake
+index a1764ad..891c4e4 100644
+--- a/cmake/os/WindowsCache.cmake
++++ b/cmake/os/WindowsCache.cmake
+@@ -74,6 +74,7 @@ SET(HAVE_FSYNC CACHE  INTERNAL "")
+ SET(HAVE_FTIME 1 CACHE  INTERNAL "")
+ SET(HAVE_FTRUNCATE CACHE  INTERNAL "")
+ SET(HAVE_GETADDRINFO 1 CACHE  INTERNAL "")
++SET(HAVE_GETIFADDRS CACHE  INTERNAL "")
+ SET(HAVE_GETCWD 1 CACHE  INTERNAL "")
+ SET(HAVE_GETHOSTBYADDR_R CACHE  INTERNAL "")
+ SET(HAVE_GETHRTIME CACHE  INTERNAL "")
+diff --git a/cmake/package_name.cmake b/cmake/package_name.cmake
+index 4cb5c95..882259c 100644
+--- a/cmake/package_name.cmake
++++ b/cmake/package_name.cmake
+@@ -27,6 +27,8 @@ IF(NOT VERSION)
+     SET(DEFAULT_MACHINE  ${CMAKE_SYSTEM_PROCESSOR})
+     IF(SIZEOF_VOIDP EQUAL 8)
+       SET(64BIT 1)
++    ELSE()
++      SET(64BIT 0)
+     ENDIF()
+     IF(CMAKE_SYSTEM_NAME MATCHES "Windows")
+@@ -127,7 +129,14 @@ IF(NOT VERSION)
+     STRING(REGEX REPLACE "^.*-ndb-" "" NDBVERSION "${VERSION}")
+     SET(package_name "mysql-cluster${PRODUCT_TAG}-${NDBVERSION}-${SYSTEM_NAME_AND_PROCESSOR}")
+   ELSE()
+-    SET(package_name "mysql${PRODUCT_TAG}-${VERSION}-${SYSTEM_NAME_AND_PROCESSOR}")
++    IF(WITH_WSREP)
++      IF(NOT WSREP_VERSION)
++        MESSAGE(FATAL_ERROR "Variable WSREP_VERSION must be set")
++      ENDIF()
++      SET(package_name "mysql-wsrep${PRODUCT_TAG}-${VERSION}-${WSREP_VERSION}-${SYSTEM_NAME_AND_PROCESSOR}")
++    ELSE()
++      SET(package_name "mysql${PRODUCT_TAG}-${VERSION}-${SYSTEM_NAME_AND_PROCESSOR}")
++    ENDIF()
+   ENDIF()
+   MESSAGE(STATUS "Packaging as: ${package_name}")
+diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
+new file mode 100644
+index 0000000..2c7d799
+--- /dev/null
++++ b/cmake/wsrep.cmake
+@@ -0,0 +1,52 @@
++# Copyright (c) 2011, Codership Oy <info@codership.com>.
++# 
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
++
++# We need to generate a proper spec file even without --with-wsrep flag,
++# so WSREP_VERSION is produced regardless
++
++# Set the patch version
++SET(WSREP_PATCH_VERSION "10")
++
++# Obtain patch revision number
++SET(WSREP_REVISION $ENV{WSREP_REV})
++IF(NOT WSREP_REVISION)
++  SET(WSREP_REVISION "XXXX" CACHE STRING "WSREP revision")
++ENDIF()
++
++
++# Obtain wsrep API version
++EXECUTE_PROCESS(
++  COMMAND sh -c "grep WSREP_INTERFACE_VERSION ${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h | cut -d '\"' -f 2"
++  OUTPUT_VARIABLE WSREP_API_VERSION
++  RESULT_VARIABLE RESULT
++)
++#FILE(WRITE "wsrep_config" "Debug: WSREP_API_VERSION result: ${RESULT}\n")
++STRING(REGEX REPLACE "(\r?\n)+$" "" WSREP_API_VERSION "${WSREP_API_VERSION}")
++
++SET(WSREP_VERSION "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}"
++  CACHE STRING "WSREP version")
++
++OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" OFF)
++IF (WITH_WSREP)
++  SET(WSREP_C_FLAGS   "-DWITH_WSREP -DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048")
++  SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} ${WSREP_C_FLAGS}")
++  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WSREP_C_FLAGS}")
++  SET(COMPILATION_COMMENT "${COMPILATION_COMMENT}, wsrep_${WSREP_VERSION}")
++  SET(WITH_EMBEDDED_SERVER OFF)
++  SET(WITH_INNODB_DISALLOW_WRITES ON)
++  SET(WITH_INNODB_MEMCACHED ON)
++ENDIF()
++
++#
+diff --git a/config.h.cmake b/config.h.cmake
+index 987be27..a216b18 100644
+--- a/config.h.cmake
++++ b/config.h.cmake
+@@ -155,6 +155,7 @@
+ #cmakedefine HAVE_FSYNC 1
+ #cmakedefine HAVE_FTIME 1
+ #cmakedefine HAVE_GETADDRINFO 1
++#cmakedefine HAVE_GETIFADDRS 1
+ #cmakedefine HAVE_GETCWD 1
+ #cmakedefine HAVE_GETHOSTBYADDR_R 1
+ #cmakedefine HAVE_GETHRTIME 1
+diff --git a/configure.cmake b/configure.cmake
+index e1c1793..a4d4809 100644
+--- a/configure.cmake
++++ b/configure.cmake
+@@ -433,6 +433,7 @@ CHECK_FUNCTION_EXISTS (getpassphrase HAVE_GETPASSPHRASE)
+ CHECK_FUNCTION_EXISTS (getpwnam HAVE_GETPWNAM)
+ CHECK_FUNCTION_EXISTS (getpwuid HAVE_GETPWUID)
+ CHECK_FUNCTION_EXISTS (getrlimit HAVE_GETRLIMIT)
++CHECK_FUNCTION_EXISTS (getifaddrs HAVE_GETIFADDRS)
+ CHECK_FUNCTION_EXISTS (getrusage HAVE_GETRUSAGE)
+ CHECK_FUNCTION_EXISTS (getwd HAVE_GETWD)
+ CHECK_FUNCTION_EXISTS (gmtime_r HAVE_GMTIME_R)
+diff --git a/include/my_md5.h b/include/my_md5.h
+index 452676e..4f89105 100644
+--- a/include/my_md5.h
++++ b/include/my_md5.h
+@@ -43,7 +43,11 @@ static inline void array_to_hex(char *to, const unsigned char *str, uint len)
+     *to++= _dig_vec_lower[((uchar) *str) & 0x0F];
+   }
+ }
+-
++#ifdef WITH_WSREP
++void *wsrep_md5_init();
++void wsrep_md5_update(void *ctx, char* buf, int len);
++  void wsrep_compute_md5_hash(char *digest, void *ctx);
++#endif
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/include/thr_lock.h b/include/thr_lock.h
+index c5638ec..6b0741f 100644
+--- a/include/thr_lock.h
++++ b/include/thr_lock.h
+@@ -20,6 +20,15 @@
+ #ifdef        __cplusplus
+ extern "C" {
+ #endif
++#ifdef WITH_WSREP
++#include <my_sys.h>
++  typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool);
++  typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool);
++  typedef int (* wsrep_on_fun)(void *);
++  void wsrep_thr_lock_init(
++    wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun,
++    my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun);
++#endif
+ #include <my_pthread.h>
+ #include <my_list.h>
+@@ -89,6 +98,10 @@ typedef struct st_thr_lock_info
+ {
+   pthread_t thread;
+   my_thread_id thread_id;
++#ifdef WITH_WSREP
++  void *mysql_thd;        // THD pointer
++  my_bool in_lock_tables; // true, if inside locking session
++#endif
+ } THR_LOCK_INFO;
+diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental
+index 2519428..1cfa4c5 100644
+--- a/mysql-test/collections/default.experimental
++++ b/mysql-test/collections/default.experimental
+@@ -21,9 +21,3 @@ rpl.rpl_gtid_logs_without_rotate_or_stop_event @windows    # Bug#16207800 2013-0
+ perfschema.socket_summary_by_instance_func  # bug#16274580
+ innodb.innodb_bug14676111                   # bug#17026780  2013-07-08 anitha Originally made experimental due to bug#16371942 which is now fixed. Now fails with mismatch in CLUST_INDEX_SIZE
+-# This file is for marking internal tests as experimental.
+-# Use the same way as the "normal" default.experimental
+-# The contents of this file will be appended to it in PB2 but not for
+-# normal developer builds.
+-# Internal tests should *not* be listed in the public default.experimental!
+-
+diff --git a/mysql-test/collections/default.release b/mysql-test/collections/default.release
+deleted file mode 100644
+index 9ac7af5..0000000
+--- a/mysql-test/collections/default.release
++++ /dev/null
+@@ -1,16 +0,0 @@
+-# This file contains the old default.release, the plan is to replace that 
+-# with something like the below (remove space after #):
+-# include default.daily
+-# include default.weekly
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=debug      --vardir=var-debug --skip-rpl --report-features --debug-server
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=normal     --vardir=var-normal --report-features --unit-tests
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=ps         --vardir=var-ps --ps-protocol
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=funcs1+ps  --vardir=var-funcs_1_ps --suite=funcs_1  --ps-protocol
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=funcs2     --vardir=var-funcs2     --suite=funcs_2
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=partitions --vardir=var-parts      --suite=parts
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=stress     --vardir=var-stress     --suite=stress
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=jp         --vardir=var-jp         --suite=jp
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=embedded   --vardir=var-embedded                    --embedded-server --skip-rpl
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=nist       --vardir=var-nist       --suite=nist
+-perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=nist+ps    --vardir=var-nist_ps    --suite=nist     --ps-protocol
+-perl mysql-test-run.pl --timer --force --comment=memcached --vardir=var-memcached --experimental=collections/default.experimental --parallel=auto --retry=0 --suite=memcached 
+diff --git a/mysql-test/collections/default.release.done b/mysql-test/collections/default.release.done
+deleted file mode 100644
+index 3d1016b..0000000
+--- a/mysql-test/collections/default.release.done
++++ /dev/null
+@@ -1 +0,0 @@
+-/export/home/pb2/build/sb_0-14135359-1421674846.01/mysql-5.6.23-release-export-7480611_gpl/mysql-test/collections/default.release.in
+diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test
+index 8a36566..c332c01 100644
+--- a/mysql-test/extra/binlog_tests/binlog.test
++++ b/mysql-test/extra/binlog_tests/binlog.test
+@@ -337,7 +337,8 @@ dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA==
+ SELECT * FROM t1;
+ --echo # Their values should be ON
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
++SHOW SESSION VARIABLES LIKE "unique_checks";
+ --echo
+ SET @@SESSION.foreign_key_checks= OFF;
+@@ -352,7 +353,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA==
+ SELECT * FROM t1;
+ --echo # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
++SHOW SESSION VARIABLES LIKE "unique_checks";
+ --echo # INSERT INTO t1 VALUES(2)
+ --echo # foreign_key_checks=1 and unique_checks=1
+@@ -366,7 +368,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA==
+ SELECT * FROM t1;
+ --echo # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
++SHOW SESSION VARIABLES LIKE "unique_checks";
+ DROP TABLE t1;
+diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
+index fe5c756..6ef3aec 100644
+--- a/mysql-test/include/check-testcase.test
++++ b/mysql-test/include/check-testcase.test
+@@ -6,6 +6,7 @@
+ # tescase.  In that way, it is possible to check that a testcase does
+ # not have any unwanted side affects.
++--source include/wait_until_connected_again.inc
+ --disable_query_log
+ # We want to ensure all slave configuration is restored.  But SHOW
+diff --git a/mysql-test/include/default_mysqld.cnf b/mysql-test/include/default_mysqld.cnf
+index cecd4a6..1c98245 100644
+--- a/mysql-test/include/default_mysqld.cnf
++++ b/mysql-test/include/default_mysqld.cnf
+@@ -34,7 +34,7 @@ loose-innodb_lru_scan_depth=      100
+ loose-innodb_write_io_threads=    2
+ loose-innodb_read_io_threads=     2
+ loose-innodb_log_buffer_size=     1M
+-loose-innodb_log_file_size=       5M
++innodb_log_file_size=       5M
+ loose-innodb_additional_mem_pool_size= 1M
+ loose-innodb_log_files_in_group=  2
+diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc
+new file mode 100644
+index 0000000..bc65222
+--- /dev/null
++++ b/mysql-test/include/galera_cluster.inc
+@@ -0,0 +1,10 @@
++# galera_cluster.inc
++# ==================
++#
++# Description
++# -----------
++# Configure galera cluster with 2 nodes.
++#
++
++--let $galera_cluster_size = 2
++--source include/galera_init.inc
+diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc
+new file mode 100644
+index 0000000..bfd9b18
+--- /dev/null
++++ b/mysql-test/include/galera_connect.inc
+@@ -0,0 +1,45 @@
++# galera_connect.inc
++# ==================
++#
++# Description
++# -----------
++# Open a connection to the specified server number ($galera_server_number).
++# The connection itself would be identified by $galera_connection_name.
++#
++# Parameters
++# ----------
++# $galera_connection_name
++#   Name of the resulting connection.
++#
++# $galera_server_number
++#   Sequence number of the node in the galera cluster.
++#
++# $galera_debug
++#   Print debug information.
++#
++
++if (!$galera_connection_name)
++{
++  --die ERROR IN TEST: $galera_connection_name must be set before sourcing include/galera_connect.inc
++}
++
++if (!$galera_server_number)
++{
++  --die ERROR IN TEST: $galera_server_number must be set before sourcing include/galera_connect.inc
++}
++
++--let $_galera_port= \$NODE_MYPORT_$galera_server_number
++if (!$_galera_port)
++{
++  --echo Bug in test case: '\$NODE_MYPORT_$galera_server_number' not initialized. Check the test's .cfg file.
++  --die Not all NODE_MYPORT_* environment variables are setup correctly.
++}
++
++if ($galera_debug)
++{
++  --echo connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
++}
++
++# Open a connection
++--connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
++
+diff --git a/mysql-test/include/galera_diff.inc b/mysql-test/include/galera_diff.inc
+new file mode 100644
+index 0000000..6043b58
+--- /dev/null
++++ b/mysql-test/include/galera_diff.inc
+@@ -0,0 +1,100 @@
++# galera_diff.inc
++# ===============
++#
++# Description
++# -----------
++# Compare the output of the given statement on all the nodes of the cluster.
++#
++# Parameters
++# ----------
++# $galera_diff_statement
++#   Statement for which the output would be compared.
++# 
++# $galera_diff_database
++#   Database against which the above statement would be executed.
++#   (Default : test)
++#
++# $galera_diff_servers
++#   Comma separated list of servers to executed the diff statement on. If not
++#   set, a list of servers will be generated based on $galera_cluster_size.
++#
++# $galerra_debug
++#   Print debug information.
++#
++
++if (!$galera_diff_statement)
++{
++  --die ERROR IN TEST: $galera_diff_statement must be set before sourcing include/galera_diff.inc
++}
++
++--let $_galera_diff_database = $galera_diff_database
++if (!$_galera_diff_database)
++{
++  --let $_galera_diff_database = test 
++}
++
++--let $_galera_diff_servers= $galera_diff_servers
++if (!$_galera_diff_servers)
++{
++  --let $_i= $galera_cluster_size
++  --let $_galera_diff_servers= 
++  while ($_i)
++  {
++    --let $_galera_diff_servers= $_i,$_galera_diff_servers
++    --dec $_i
++  }
++}
++if ($galera_debug)
++{
++  --echo \$galera_diff_servers= '$_galera_diff_servers'
++}
++
++if (!$galera_debug)
++{
++  --disable_query_log
++}
++
++# Generate file containing $galera_diff_statement. We don't pass the
++# statement on the command line, because it would be subject to shell
++# substitutions.
++--let $write_to_file= GENERATE
++--let $write_var= $galera_diff_statement
++--source include/write_var_to_file.inc
++--let $_galera_diff_statement_file= $write_to_file
++
++if (!$galera_debug)
++{
++  --enable_query_log
++}
++
++# Compare all servers.
++--let $_galera_diff_first= 1
++while ($_galera_diff_servers)
++{
++  # Set $_galera_diff_server_i to the first number in the list
++  --let $_galera_diff_server_i= `SELECT SUBSTRING_INDEX('$_galera_diff_servers', ',', 1)`
++  # Remove $_galera_diff_server_i from the list
++  --let $_galera_diff_servers= `SELECT SUBSTRING('$_galera_diff_servers', LENGTH('$_galera_diff_server_i') + 2)`
++
++  # Execute statement
++  --let $_galera_diff_file= $MYSQLTEST_VARDIR/tmp/_galera_diff_server-$_galera_diff_server_i.tmp
++  --exec $MYSQL --defaults-group-suffix=.$_galera_diff_server_i $_galera_diff_database < $_galera_diff_statement_file > $_galera_diff_file
++
++  # Compare
++  if (!$_galera_diff_first)
++  {
++    if ($galera_debug)
++    {
++      --echo diffing $_galera_diff_file and $_galera_diff_prev_file
++    }
++    --diff_files $_galera_diff_file $_galera_diff_prev_file
++    --remove_file $_galera_diff_prev_file
++  }
++  --let $_galera_diff_prev_file= $_galera_diff_file
++  --let $_galera_diff_first= 0
++}
++
++# Cleanup
++--remove_file $_galera_diff_prev_file
++--remove_file $_galera_diff_statement_file
++
+diff --git a/mysql-test/include/galera_end.inc b/mysql-test/include/galera_end.inc
+new file mode 100644
+index 0000000..0fb5479
+--- /dev/null
++++ b/mysql-test/include/galera_end.inc
+@@ -0,0 +1,25 @@
++# galera_end.inc
++# ==============
++#
++# Description
++# -----------
++# Closes the connections opened via include/galera_init.inc
++#
++# Parameters
++# ----------
++# $galera_cluster_size
++#   Number of nodes in the cluster.
++#
++
++--let $_galera_node= $galera_cluster_size
++
++while ($_galera_node)
++{
++  if ($galera_debug)
++  {
++    --echo Disconnecting node_$_galera_node
++  }
++  --disconnect node_$_galera_node
++  --dec $_galera_node
++}
++
+diff --git a/mysql-test/include/galera_init.inc b/mysql-test/include/galera_init.inc
+new file mode 100644
+index 0000000..7c79d6f
+--- /dev/null
++++ b/mysql-test/include/galera_init.inc
+@@ -0,0 +1,27 @@
++# galera_init.inc
++# ===============
++#
++# Description
++# -----------
++# Set up a Galera cluster with $wsrep_cluster_size nodes.
++#
++# Parameters
++# ----------
++# $galera_cluster_size
++#   Number of nodes in the cluster.
++#
++
++--source include/have_wsrep_provider.inc
++--source include/have_wsrep_enabled.inc
++
++--let $_galera_node= $galera_cluster_size
++
++while ($_galera_node)
++{
++  --let $galera_connection_name= node_$_galera_node
++  --let $galera_server_number= $_galera_node
++  --source include/galera_connect.inc
++
++  --dec $_galera_node
++}
++
+diff --git a/mysql-test/include/galera_resume.inc b/mysql-test/include/galera_resume.inc
+new file mode 100644
+index 0000000..232cb46
+--- /dev/null
++++ b/mysql-test/include/galera_resume.inc
+@@ -0,0 +1,9 @@
++--echo Resuming node ...
++--perl
++        my $pid_filename = $ENV{'_SUSPEND_NODE_PIDFILE'};
++        my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++        system("kill -18 $mysqld_pid");
++        exit(0);
++EOF
++
+diff --git a/mysql-test/include/galera_suspend.inc b/mysql-test/include/galera_suspend.inc
+new file mode 100644
+index 0000000..3495ad2
+--- /dev/null
++++ b/mysql-test/include/galera_suspend.inc
+@@ -0,0 +1,14 @@
++#
++# This macro suspends the current node
++#
++
++--let _SUSPEND_NODE_PIDFILE = `SELECT @@pid_file`
++--echo Suspending node ...
++
++--perl
++        my $pid_filename = $ENV{'_SUSPEND_NODE_PIDFILE'};
++        my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++        system("kill -19 $mysqld_pid");
++        exit(0);
++EOF
+diff --git a/mysql-test/include/galera_wait_ready.inc b/mysql-test/include/galera_wait_ready.inc
+new file mode 100644
+index 0000000..5652538
+--- /dev/null
++++ b/mysql-test/include/galera_wait_ready.inc
+@@ -0,0 +1,3 @@
++let $wait_timeout = 10;
++let $wait_condition = SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready' AND VARIABLE_VALUE = 'ON';
++--source include/wait_condition.inc
+diff --git a/mysql-test/include/have_wsrep.inc b/mysql-test/include/have_wsrep.inc
+new file mode 100644
+index 0000000..52220ed
+--- /dev/null
++++ b/mysql-test/include/have_wsrep.inc
+@@ -0,0 +1,8 @@
++# To be used in a test which requires server to be compiled with wsrep support
++# (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE.
++
++if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`)
++{
++  --skip Test requires wsrep plugin.
++}
++
+diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc
+new file mode 100644
+index 0000000..1b5948f
+--- /dev/null
++++ b/mysql-test/include/have_wsrep_enabled.inc
+@@ -0,0 +1,10 @@
++
++# To be used in a test which requires wsrep plugin to be ACTIVE and enabled
++# (i.e. wsrep_on=ON). It includes have_wsrep.inc.
++
++--source include/have_wsrep.inc
++
++--require r/have_wsrep.require
++--disable_query_log
++SHOW VARIABLES LIKE 'wsrep_on';
++--enable_query_log
+diff --git a/mysql-test/include/have_wsrep_provider.inc b/mysql-test/include/have_wsrep_provider.inc
+new file mode 100644
+index 0000000..bb5cbc0
+--- /dev/null
++++ b/mysql-test/include/have_wsrep_provider.inc
+@@ -0,0 +1,6 @@
++if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE
++    VARIABLE_NAME LIKE 'wsrep_provider' AND VARIABLE_VALUE NOT LIKE 'none'`)
++{
++  --skip Test requires wsrep provider library (libgalera_smm.so). Did you set $WSREP_PROVIDER?
++}
++
+diff --git a/mysql-test/include/kill_galera.inc b/mysql-test/include/kill_galera.inc
+new file mode 100644
+index 0000000..d7f665d
+--- /dev/null
++++ b/mysql-test/include/kill_galera.inc
+@@ -0,0 +1,20 @@
++--echo Killing server ...
++
++# Write file to make mysql-test-run.pl expect the crash, but don't start it
++--let $_server_id= `SELECT @@server_id`
++--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
++--exec echo "wait" > $_expect_file_name
++
++# Kill the connected server
++--disable_reconnect
++--let KILL_NODE_PIDFILE = `SELECT @@pid_file`
++
++--perl
++        my $pid_filename = $ENV{'KILL_NODE_PIDFILE'};
++        my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++        system("kill -9 $mysqld_pid");
++        exit(0);
++EOF
++
++--source include/wait_until_disconnected.inc
+diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql
+index 3bd2583..560dd96 100644
+--- a/mysql-test/include/mtr_check.sql
++++ b/mysql-test/include/mtr_check.sql
+@@ -60,15 +60,23 @@ BEGIN
+   -- Dump all global variables except those that may change.
+   -- timestamp changes if time passes. server_uuid changes if server restarts.
++  -- wsrep_start_position can change on mysqldump SST
++  -- auto_increment_offset can change on cluster reconfigurations
+   SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
+     WHERE variable_name NOT IN ('timestamp', 'server_uuid',
+                                 'innodb_file_format_max',
+-                                'gtid_executed', 'gtid_purged')
++                                'gtid_executed', 'gtid_purged',
++                                'wsrep_start_position',
++                                'auto_increment_offset',
++                                'auto_increment_increment',
++                                'wsrep_data_home_dir')
+     ORDER BY VARIABLE_NAME;
+   -- Dump all databases, there should be none
+   -- except those that was created during bootstrap
+-  SELECT * FROM INFORMATION_SCHEMA.SCHEMATA;
++  -- and the mtr_wsrep_notify schema which is populated by the std_data/wsrep_notify.sh script
++  -- and the suite/galera/t/galera_var_notify_cmd.test
++  SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME != 'mtr_wsrep_notify';
+   -- The test database should not contain any tables
+   SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES
+diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql
+index 9de3058..3b7f559 100644
+--- a/mysql-test/include/mtr_warnings.sql
++++ b/mysql-test/include/mtr_warnings.sql
+@@ -246,6 +246,40 @@ INSERT INTO global_suppressions VALUES
+  ("Changed limits: table_cache: *"),
+  ("Could not increase number of max_open_files to more than *"),
++ /*
++   Galera suppressions 
++ */
++ ("WSREP:*down context*"),
++ ("WSREP: Failed to send state UUID:*"),
++ ("WSREP: wsrep_sst_receive_address is set to '127.0.0.1"),
++ ("WSREP: option --wsrep-casual-reads is deprecated"),
++ ("WSREP: --wsrep-casual-reads=ON takes precedence over --wsrep-sync-wait=0"),
++ ("WSREP: Could not open saved state file for reading: "),
++ ("WSREP: access file\\(.*gvwstate\\.dat\\) failed\\(No such file or directory\\)"),
++ ("WSREP: Gap in state sequence\\. Need state transfer\\."),
++ ("WSREP: Failed to prepare for incremental state transfer: Local state UUID \\(00000000-0000-0000-0000-000000000000\\) does not match group state UUID"),
++ ("WSREP: No existing UUID has been found, so we assume that this is the first time that this server has been started\\. Generating a new UUID: "),
++ ("WSREP: last inactive check more than"),
++ ("WSREP: binlog cache not empty \\(0 bytes\\) at connection close"),
++ ("WSREP: SQL statement was ineffective"),
++ ("WSREP: Refusing exit for the last slave thread"),
++ ("WSREP: Quorum: No node with complete state"),
++ ("WSREP: Failed to report last committed"),
++ ("Slave SQL: Error 'Duplicate entry"),
++ ("Query apply warning:"),
++ ("WSREP: Ignoring error for TO isolated action:"),
++ ("WSREP: Initial position was provided by configuration or SST, avoiding override"),
++ ("Warning: Using a password on the command line interface can be insecure"),
++ ("InnoDB: Error: Table \"mysql\"\\.\"innodb_table_stats\" not found"),
++ ("but it is impossible to select State Transfer donor: Resource temporarily unavailable"),
++ ("WSREP: Could not find peer"),
++ ("WSREP: discarding established \\(time wait\\)"),
++ ("sending install message failed: Resource temporarily unavailable"),
++ ("WSREP: Ignoring possible split-brain \\(allowed by configuration\\) from view"),
++ ("WSREP: no nodes coming from prim view, prim not possible"),
++ ("WSREP: Failed to prepare for incremental state transfer: Local state seqno is undefined:"),
++ ("WSREP: gcs_caused\\(\\) returned -107 \\(Transport endpoint is not connected\\)"),
++
+  ("THE_LAST_SUPPRESSION")||
+@@ -292,7 +326,17 @@ BEGIN
+   END IF;
+   -- Cleanup for next test
+-  TRUNCATE test_suppressions;
++  IF @@wsrep_on = 1 THEN
++    -- The TRUNCATE should not be replicated under Galera
++    -- as it causes the custom suppressions on the other
++    -- nodes to be deleted as well
++    SET wsrep_on = 0;
++    TRUNCATE test_suppressions;
++    SET wsrep_on = 1;
++  ELSE 
++    TRUNCATE test_suppressions;
++  END IF;    
++
+   DROP TABLE error_log;
+ END||
+diff --git a/mysql-test/include/mysqld--help.inc b/mysql-test/include/mysqld--help.inc
+index e156cfd..8b3b387 100644
+--- a/mysql-test/include/mysqld--help.inc
++++ b/mysql-test/include/mysqld--help.inc
+@@ -18,7 +18,7 @@ perl;
+   # their paths may vary:
+   @skipvars=qw/basedir open-files-limit general-log-file plugin-dir
+                pid-file slow-query-log-file
+-                         datadir slave-load-tmpdir tmpdir socket table-definition-cache table-open-cache/;
++                         datadir slave-load-tmpdir tmpdir socket table-definition-cache table-open-cache wsrep-node-name/;
+   # Plugins which may or may not be there:
+   @plugins=qw/innodb ndb ndbinfo archive blackhole federated partition ndbcluster debug temp-pool ssl des-key-file
+diff --git a/mysql-test/include/not_wsrep.inc b/mysql-test/include/not_wsrep.inc
+new file mode 100644
+index 0000000..3314b5c
+--- /dev/null
++++ b/mysql-test/include/not_wsrep.inc
+@@ -0,0 +1,7 @@
++# To be used in a test which should be skipped if server is compiled with wsrep
++# support (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE.
++
++-- require r/not_wsrep.require
++disable_query_log;
++SELECT VERSION() LIKE '%wsrep%' AS 'HAVE_WSREP';
++enable_query_log;
+diff --git a/mysql-test/include/start_mysqld.inc b/mysql-test/include/start_mysqld.inc
+index 983c566..4ee3d17 100644
+--- a/mysql-test/include/start_mysqld.inc
++++ b/mysql-test/include/start_mysqld.inc
+@@ -1,7 +1,16 @@
+ # Include this script only after using shutdown_mysqld.inc
+ # where $_expect_file_name was initialized.
+ # Write file to make mysql-test-run.pl start up the server again
+---exec echo "restart" > $_expect_file_name
++
++if ($galera_wsrep_start_position != '') {
++      --echo Using --wsrep-start-position when starting mysqld ...
++      --exec echo "restart:$start_mysqld_params --wsrep-start-position=$galera_wsrep_start_position" > $_expect_file_name
++      --let $galera_wsrep_start_position = 0
++}
++
++if ($galera_wsrep_start_position == '') {
++      --exec echo "restart:$start_mysqld_params" > $_expect_file_name
++}
+ # Turn on reconnect
+ --enable_reconnect
+@@ -11,4 +20,3 @@
+ # Turn off reconnect again
+ --disable_reconnect
+-
+diff --git a/mysql-test/include/wait_until_connected_again.inc b/mysql-test/include/wait_until_connected_again.inc
+index c7bb774..005d518 100644
+--- a/mysql-test/include/wait_until_connected_again.inc
++++ b/mysql-test/include/wait_until_connected_again.inc
+@@ -1,23 +1,34 @@
+ #
+ # Include this script to wait until the connection to the
+ # server has been restored or timeout occurs
++
++#
++# We require two consequtive connection successes in order to
++# work around a race condition on Galera startup where the server
++# can temporarily accept queries before starting to reject them again
++#
++
+ --disable_result_log
+ --disable_query_log
+ let $counter= 500;
+ let $mysql_errno= 9999;
+-while ($mysql_errno)
+-{
+-  # Strangely enough, the server might return "Too many connections"
+-  # while being shutdown, thus 1040 is an "allowed" error
+-  # See BUG#36228
+-  --error 0,1040,1053,2002,2003,2006,2013
+-  show status;
++let $successes= 2;
++
++while ($successes) {
++  while ($mysql_errno) {
++    # Strangely enough, the server might return "Too many connections"
++    # while being shutdown, thus 1040 is an "allowed" error
++    # See BUG#36228
++    --error 0,1040,1047,1053,1205,2002,2003,2006,2013,1205
++    show status;
+-  dec $counter;
+-  if (!$counter)
+-  {
+-    --die Server failed to restart
++    --dec $counter
++    if (!$counter) {
++      --die Server failed to restart
++    }
++     --sleep 0.1
+   }
++  --dec $successes
+   --sleep 0.1
+ }
+ --enable_query_log
+diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc
+index 8a989be..56889d1 100644
+--- a/mysql-test/include/wait_until_disconnected.inc
++++ b/mysql-test/include/wait_until_disconnected.inc
+@@ -7,7 +7,7 @@ let $counter= 500;
+ let $mysql_errno= 0;
+ while (!$mysql_errno)
+ {
+-  --error 0,1040,1053,2002,2003,2006,2013
++  --error 0,1040,1047,1053,2002,2003,2006,2013
+   show status;
+   dec $counter;
+diff --git a/mysql-test/include/write_var_to_file.inc b/mysql-test/include/write_var_to_file.inc
+index 8bb9e72..6ee04c7 100644
+--- a/mysql-test/include/write_var_to_file.inc
++++ b/mysql-test/include/write_var_to_file.inc
+@@ -54,7 +54,7 @@ if (`SELECT LENGTH(@@secure_file_priv) > 0`)
+   --copy_file $_wvtf_tmp_file $write_to_file
+   --remove_file $_wvtf_tmp_file
+ }
+-if (`SELECT LENGTH(@@secure_file_priv) = 0`)
++if (`SELECT LENGTH(@@secure_file_priv) = 0 OR LENGTH(@@secure_file_priv) IS NULL`)
+ {
+   --eval SELECT '$write_var' INTO DUMPFILE '$write_to_file'
+ }
+diff --git a/mysql-test/lib/My/Config.pm b/mysql-test/lib/My/Config.pm
+index 535df07..642ee0a 100644
+--- a/mysql-test/lib/My/Config.pm
++++ b/mysql-test/lib/My/Config.pm
+@@ -178,6 +178,36 @@ sub if_exist {
+   return $option->value();
+ }
++package My::Config::Group::ENV;
++our @ISA=qw(My::Config::Group);
++
++use strict;
++use warnings;
++use Carp;
++
++sub new {
++  my ($class, $group_name)= @_;
++  bless My::Config::Group->new($group_name), $class;
++}
++
++#
++# Return value for an option in the group, fail if it does not exist
++#
++sub value {
++  my ($self, $option_name)= @_;
++  my $option= $self->option($option_name);
++
++  if (! defined($option) and defined $ENV{$option_name}) {
++    my $value= $ENV{$option_name};
++    $option= My::Config::Option->new($option_name, $value);
++  }
++
++  croak "No option named '$option_name' in group '$self->{name}'"
++    if ! defined($option);
++
++  return $option->value();
++}
++
+ package My::Config;
+@@ -197,7 +227,9 @@ sub new {
+   my ($class, $path)= @_;
+   my $group_name= undef;
+-  my $self= bless { groups => [] }, $class;
++  my $self= bless { groups => [
++      My::Config::Group::ENV->new('ENV')
++    ] }, $class;
+   my $F= IO::File->new($path, "<")
+     or croak "Could not open '$path': $!";
+diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm
+index bf2a8fa..fca7f9d 100644
+--- a/mysql-test/lib/My/ConfigFactory.pm
++++ b/mysql-test/lib/My/ConfigFactory.pm
+@@ -1,5 +1,5 @@
+ # -*- cperl -*-
+-# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
++# Copyright (c) 2007, 2011, Oracle and/or its affiliates
+ #
+ # This program is free software; you can redistribute it and/or
+ # modify it under the terms of the GNU Library General Public
+@@ -31,12 +31,22 @@ use File::Basename;
+ #
+ # Rules to run first of all
+ #
++
++sub add_opt_values {
++  my ($self, $config)= @_;
++
++  # add auto-options
++  $config->insert('OPT', 'port'   => sub { fix_port($self, $config) });
++  $config->insert('mysqld', "loose-skip-plugin-$_" => undef) for (@::optional_plugins);
++}
++
+ my @pre_rules=
+ (
++  \&add_opt_values,
+ );
+-my @share_locations= ("share/mysql", "sql/share", "share");
++my @share_locations= ("share/mariadb", "share/mysql", "sql/share", "share");
+ sub get_basedir {
+@@ -89,16 +99,12 @@ sub fix_pidfile {
+ sub fix_port {
+   my ($self, $config, $group_name, $group)= @_;
+-  my $hostname= $group->value('#host');
+-  return $self->{HOSTS}->{$hostname}++;
++  return $self->{PORT}++;
+ }
+ sub fix_host {
+   my ($self)= @_;
+-  # Get next host from HOSTS array
+-  my @hosts= keys(%{$self->{HOSTS}});;
+-  my $host_no= $self->{NEXT_HOST}++ % @hosts;
+-  return $hosts[$host_no];
++  'localhost'
+ }
+ sub is_unique {
+@@ -169,13 +175,6 @@ sub fix_log_slow_queries {
+   return "$dir/mysqld-slow.log";
+ }
+-sub fix_secure_file_priv {
+-  my ($self)= @_;
+-  my $vardir= $self->{ARGS}->{vardir};
+-  # By default, prevent the started mysqld to access files outside of vardir
+-  return $vardir;
+-}
+-
+ sub fix_std_data {
+   my ($self, $config, $group_name, $group)= @_;
+   my $testdir= $self->get_testdir($group);
+@@ -239,12 +238,18 @@ my @mysqld_rules=
+  { 'pid-file' => \&fix_pidfile },
+  { '#host' => \&fix_host },
+  { 'port' => \&fix_port },
++ # galera base_port and port used during SST
++ { '#galera_port' => \&fix_port },
++ # Galera uses base_port + 1 for IST, so we do not use it for things such as SST
++ { '#ist_port' => \&fix_port },
++ { '#sst_port' => \&fix_port },
+  { 'socket' => \&fix_socket },
+  { '#log-error' => \&fix_log_error },
+- { 'general_log' => 1 },
+- { 'general_log_file' => \&fix_log },
+- { 'slow_query_log' => 1 },
+- { 'slow_query_log_file' => \&fix_log_slow_queries },
++ { 'general-log' => 1 },
++ { 'plugin-dir' => sub { $::plugindir } },
++ { 'general-log-file' => \&fix_log },
++ { 'slow-query-log' => 1 },
++ { 'slow-query-log-file' => \&fix_log_slow_queries },
+  { '#user' => sub { return shift->{ARGS}->{user} || ""; } },
+  { '#password' => sub { return shift->{ARGS}->{password} || ""; } },
+  { 'server-id' => \&fix_server_id, },
+@@ -265,7 +270,7 @@ if (IS_WINDOWS)
+ sub fix_ndb_mgmd_port {
+   my ($self, $config, $group_name, $group)= @_;
+   my $hostname= $group->value('HostName');
+-  return $self->{HOSTS}->{$hostname}++;
++  return $self->{PORT}++;
+ }
+@@ -307,8 +312,6 @@ my @ndbd_rules=
+  { 'BackupDataDir' => \&fix_cluster_backup_dir },
+ );
+-
+-#
+ # Rules to run for each memcached in the config
+ #  - will be run in order listed here
+ #
+@@ -396,7 +399,7 @@ sub post_check_client_group {
+     if (! defined $option){
+       #print $config;
+-      croak "Could not get value for '$name_from'";
++      croak "Could not get value for '$name_from' for test $self->{testname}";
+     }
+     $config->insert($client_group_name, $name_to, $option->value())
+   }
+@@ -419,7 +422,7 @@ sub post_check_client_group {
+ sub post_check_client_groups {
+  my ($self, $config)= @_;
+- my $first_mysqld= $config->first_like('mysqld.');
++ my $first_mysqld= $config->first_like('mysqld\.');
+  return unless $first_mysqld;
+@@ -455,7 +458,7 @@ sub post_check_embedded_group {
+   my $first_mysqld= $config->first_like('mysqld.') or
+     croak "Can't run with embedded, config has no mysqld";
+-  my @no_copy =
++  my %no_copy = map { $_ => 1 }
+     (
+      '#log-error', # Embedded server writes stderr to mysqltest's log file
+      'slave-net-timeout', # Embedded server are not build with replication
+@@ -464,7 +467,7 @@ sub post_check_embedded_group {
+   foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
+     # Don't copy options whose name is in "no_copy" list
+-    next if grep ( $option->name() eq $_, @no_copy);
++    next if $no_copy{$option->name()};
+     $config->insert('embedded', $option->name(), $option->value())
+   }
+@@ -474,20 +477,24 @@ sub post_check_embedded_group {
+ sub resolve_at_variable {
+   my ($self, $config, $group, $option)= @_;
++  local $_ = $option->value();
++  my ($res, $after);
+-  # Split the options value on last .
+-  my @parts= split(/\./, $option->value());
+-  my $option_name= pop(@parts);
+-  my $group_name=  join('.', @parts);
+-
+-  $group_name =~ s/^\@//; # Remove at
++  while (m/(.*?)\@((?:\w+\.)+)(#?[-\w]+)/g) {
++    my ($before, $group_name, $option_name)= ($1, $2, $3);
++    $after = $';
++    chop($group_name);
+   my $from_group= $config->group($group_name)
+     or croak "There is no group named '$group_name' that ",
+-      "can be used to resolve '$option_name'";
++      "can be used to resolve '$option_name' for test '$self->{testname}'";
+-  my $from= $from_group->value($option_name);
+-  $config->insert($group->name(), $option->name(), $from)
++    my $value= $from_group->value($option_name);
++    $res .= $before.$value;
++  }
++  $res .= $after;
++
++  $config->insert($group->name(), $option->name(), $res)
+ }
+@@ -499,7 +506,7 @@ sub post_fix_resolve_at_variables {
+       next unless defined $option->value();
+       $self->resolve_at_variable($config, $group, $option)
+-      if ($option->value() =~ /^\@/);
++      if ($option->value() =~ /\@/);
+     }
+   }
+ }
+@@ -641,37 +648,21 @@ sub new_config {
+     croak "you must pass '$required'" unless defined $args->{$required};
+   }
+-  # Fill in hosts/port hash
+-  my $hosts= {};
+-  my $baseport= $args->{baseport};
+-  $args->{hosts}= [ 'localhost' ] unless exists($args->{hosts});
+-  foreach my $host ( @{$args->{hosts}} ) {
+-     $hosts->{$host}= $baseport;
+-  }
+-
+   # Open the config template
+   my $config= My::Config->new($args->{'template_path'});
+-  my $extra_template_path= $args->{'extra_template_path'};
+-  if ($extra_template_path){
+-    $config->append(My::Config->new($extra_template_path));
+-  }
+   my $self= bless {
+                  CONFIG       => $config,
+                  ARGS         => $args,
+-                 HOSTS        => $hosts,
+-                 NEXT_HOST    => 0,
++                 PORT         => $args->{baseport},
+                  SERVER_ID    => 1,
++                   testname     => $args->{testname},
+                 }, $class;
+-
+-  {
+-    # Run pre rules
+-    foreach my $rule ( @pre_rules ) {
+-      &$rule($self, $config);
+-    }
++  # Run pre rules
++  foreach my $rule ( @pre_rules ) {
++    &$rule($self, $config);
+   }
+-
+   $self->run_section_rules($config,
+                          'cluster_config\.\w*$',
+                          @cluster_config_rules);
+@@ -689,9 +680,9 @@ sub new_config {
+                          @mysqld_rules);
+   $self->run_section_rules($config,
+-                         'memcached.',
+-                         @memcached_rules);
+-               
++                          'memcached.',
++                          @memcached_rules);
++
+   # [mysqlbinlog] need additional settings
+   $self->run_rules_for_group($config,
+                            $config->insert('mysqlbinlog'),
+diff --git a/mysql-test/lib/My/ConfigFactory.pm.memcached b/mysql-test/lib/My/ConfigFactory.pm.memcached
+new file mode 100644
+index 0000000..0b0e468
+--- /dev/null
++++ b/mysql-test/lib/My/ConfigFactory.pm.memcached
+@@ -0,0 +1,718 @@
++# -*- cperl -*-
++# Copyright (c) 2007, 2011, Oracle and/or its affiliates
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Library General Public
++# License as published by the Free Software Foundation; version 2
++# of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# Library General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++
++package My::ConfigFactory;
++
++use strict;
++use warnings;
++use Carp;
++
++use My::Config;
++use My::Find;
++use My::Platform;
++
++use File::Basename;
++
++
++#
++# Rules to run first of all
++#
++
++sub add_opt_values {
++  my ($self, $config)= @_;
++
++  # add auto-options
++  $config->insert('OPT', 'port'   => sub { fix_port($self, $config) });
++  $config->insert('mysqld', "loose-skip-plugin-$_" => undef) for (@::optional_plugins);
++}
++
++my @pre_rules=
++(
++  \&add_opt_values,
++);
++
++
++my @share_locations= ("share/mariadb", "share/mysql", "sql/share", "share");
++
++
++sub get_basedir {
++  my ($self, $group)= @_;
++  my $basedir= $group->if_exist('basedir') ||
++    $self->{ARGS}->{basedir};
++  return $basedir;
++}
++
++sub get_testdir {
++  my ($self, $group)= @_;
++  my $testdir= $group->if_exist('testdir') ||
++    $self->{ARGS}->{testdir};
++  return $testdir;
++}
++
++# Retrive build directory (which is different from basedir in out-of-source build)
++sub get_bindir {
++  if (defined $ENV{MTR_BINDIR})
++  {
++    return $ENV{MTR_BINDIR};
++  }
++  my ($self, $group)= @_;
++  return $self->get_basedir($group);
++}
++
++sub fix_charset_dir {
++  my ($self, $config, $group_name, $group)= @_;
++  return my_find_dir($self->get_basedir($group),
++                   \@share_locations, "charsets");
++}
++
++sub fix_language {
++  my ($self, $config, $group_name, $group)= @_;
++  return my_find_dir($self->get_bindir($group),
++                   \@share_locations);
++}
++
++sub fix_datadir {
++  my ($self, $config, $group_name)= @_;
++  my $vardir= $self->{ARGS}->{vardir};
++  return "$vardir/$group_name/data";
++}
++
++sub fix_pidfile {
++  my ($self, $config, $group_name, $group)= @_;
++  my $vardir= $self->{ARGS}->{vardir};
++  return "$vardir/run/$group_name.pid";
++}
++
++sub fix_port {
++  my ($self, $config, $group_name, $group)= @_;
++  return $self->{PORT}++;
++}
++
++sub fix_host {
++  my ($self)= @_;
++  'localhost'
++}
++
++sub is_unique {
++  my ($config, $name, $value)= @_;
++
++  foreach my $group ( $config->groups() ) {
++    if ($group->option($name)) {
++      if ($group->value($name) eq $value){
++      return 0;
++      }
++    }
++  }
++  return 1;
++}
++
++sub fix_server_id {
++  my ($self, $config, $group_name, $group)= @_;
++#define in the order that mysqlds are listed in my.cnf 
++
++  my $server_id= $group->if_exist('server-id');
++  if (defined $server_id){
++    if (!is_unique($config, 'server-id', $server_id)) {
++      croak "The server-id($server_id) for '$group_name' is not unique";
++    }
++    return $server_id;
++  }
++
++  do {
++    $server_id= $self->{SERVER_ID}++;
++  } while(!is_unique($config, 'server-id', $server_id));
++
++  #print "$group_name: server_id: $server_id\n";
++  return $server_id;
++}
++
++sub fix_socket {
++  my ($self, $config, $group_name, $group)= @_;
++  # Put socket file in tmpdir
++  my $dir= $self->{ARGS}->{tmpdir};
++  return "$dir/$group_name.sock";
++}
++
++sub fix_tmpdir {
++  my ($self, $config, $group_name, $group)= @_;
++  my $dir= $self->{ARGS}->{tmpdir};
++  return "$dir/$group_name";
++}
++
++sub fix_log_error {
++  my ($self, $config, $group_name, $group)= @_;
++  my $dir= $self->{ARGS}->{vardir};
++  if ( $::opt_valgrind and $::opt_debug ) {
++    return "$dir/log/$group_name.trace";
++  } else {
++    return "$dir/log/$group_name.err";
++  }
++}
++
++sub fix_log {
++  my ($self, $config, $group_name, $group)= @_;
++  my $dir= dirname($group->value('datadir'));
++  return "$dir/mysqld.log";
++}
++
++sub fix_log_slow_queries {
++  my ($self, $config, $group_name, $group)= @_;
++  my $dir= dirname($group->value('datadir'));
++  return "$dir/mysqld-slow.log";
++}
++
++sub fix_std_data {
++  my ($self, $config, $group_name, $group)= @_;
++  my $testdir= $self->get_testdir($group);
++  return "$testdir/std_data";
++}
++
++sub ssl_supported {
++  my ($self)= @_;
++  return $self->{ARGS}->{ssl};
++}
++
++sub fix_skip_ssl {
++  return if !ssl_supported(@_);
++  # Add skip-ssl if ssl is supported to avoid
++  # that mysqltest connects with SSL by default
++  return 1;
++}
++
++sub fix_ssl_ca {
++  return if !ssl_supported(@_);
++  my $std_data= fix_std_data(@_);
++  return "$std_data/cacert.pem"
++}
++
++sub fix_ssl_server_cert {
++  return if !ssl_supported(@_);
++  my $std_data= fix_std_data(@_);
++  return "$std_data/server-cert.pem"
++}
++
++sub fix_ssl_client_cert {
++  return if !ssl_supported(@_);
++  my $std_data= fix_std_data(@_);
++  return "$std_data/client-cert.pem"
++}
++
++sub fix_ssl_server_key {
++  return if !ssl_supported(@_);
++  my $std_data= fix_std_data(@_);
++  return "$std_data/server-key.pem"
++}
++
++sub fix_ssl_client_key {
++  return if !ssl_supported(@_);
++  my $std_data= fix_std_data(@_);
++  return "$std_data/client-key.pem"
++}
++
++
++#
++# Rules to run for each mysqld in the config
++#  - will be run in order listed here
++#
++my @mysqld_rules=
++  (
++ { 'basedir' => sub { return shift->{ARGS}->{basedir}; } },
++ { 'tmpdir' => \&fix_tmpdir },
++ { 'character-sets-dir' => \&fix_charset_dir },
++ { 'lc-messages-dir' => \&fix_language },
++ { 'datadir' => \&fix_datadir },
++ { 'pid-file' => \&fix_pidfile },
++ { '#host' => \&fix_host },
++ { 'port' => \&fix_port },
++ # galera base_port and port used during SST
++ { '#galera_port' => \&fix_port },
++ { '#sst_port' => \&fix_port },
++ { '#memcached_port' => \&fix_port },
++ { 'socket' => \&fix_socket },
++ { '#log-error' => \&fix_log_error },
++ { 'general-log' => 1 },
++ { 'plugin-dir' => sub { $::plugindir } },
++ { 'general-log-file' => \&fix_log },
++ { 'slow-query-log' => 1 },
++ { 'slow-query-log-file' => \&fix_log_slow_queries },
++ { '#user' => sub { return shift->{ARGS}->{user} || ""; } },
++ { '#password' => sub { return shift->{ARGS}->{password} || ""; } },
++ { 'server-id' => \&fix_server_id, },
++ # By default, prevent the started mysqld to access files outside of vardir
++ { 'secure-file-priv' => sub { return shift->{ARGS}->{vardir}; } },
++ { 'ssl-ca' => \&fix_ssl_ca },
++ { 'ssl-cert' => \&fix_ssl_server_cert },
++ { 'ssl-key' => \&fix_ssl_server_key },
++  );
++
++if (IS_WINDOWS)
++{
++  # For simplicity, we use the same names for shared memory and 
++  # named pipes.
++  push(@mysqld_rules, {'shared-memory-base-name' => \&fix_socket});
++}
++ 
++sub fix_ndb_mgmd_port {
++  my ($self, $config, $group_name, $group)= @_;
++  my $hostname= $group->value('HostName');
++  return $self->{PORT}++;
++}
++
++
++sub fix_cluster_dir {
++  my ($self, $config, $group_name, $group)= @_;
++  my $vardir= $self->{ARGS}->{vardir};
++  my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
++  return "$vardir/mysql_cluster.$suffix/$process_type.$idx";
++}
++
++
++sub fix_cluster_backup_dir {
++  my ($self, $config, $group_name, $group)= @_;
++  my $vardir= $self->{ARGS}->{vardir};
++  my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
++  return "$vardir/mysql_cluster.$suffix/";
++}
++
++
++#
++# Rules to run for each ndb_mgmd in the config
++#  - will be run in order listed here
++#
++my @ndb_mgmd_rules=
++(
++ { 'PortNumber' => \&fix_ndb_mgmd_port },
++ { 'DataDir' => \&fix_cluster_dir },
++);
++
++
++#
++# Rules to run for each ndbd in the config
++#  - will be run in order listed here
++#
++my @ndbd_rules=
++(
++ { 'HostName' => \&fix_host },
++ { 'DataDir' => \&fix_cluster_dir },
++ { 'BackupDataDir' => \&fix_cluster_backup_dir },
++);
++
++# Rules to run for each memcached in the config
++#  - will be run in order listed here
++#
++my @memcached_rules=
++(
++ { '#host' => \&fix_host },
++ { 'port' => \&fix_port },
++);
++
++#
++# Rules to run for each cluster_config section
++#  - will be run in order listed here
++#
++my @cluster_config_rules=
++(
++ { 'ndb_mgmd' => \&fix_host },
++ { 'ndbd' => \&fix_host },
++ { 'mysqld' => \&fix_host },
++ { 'ndbapi' => \&fix_host },
++);
++
++
++#
++# Rules to run for [client] section
++#  - will be run in order listed here
++#
++my @client_rules=
++(
++);
++
++
++#
++# Rules to run for [mysqltest] section
++#  - will be run in order listed here
++#
++my @mysqltest_rules=
++(
++ { 'ssl-ca' => \&fix_ssl_ca },
++ { 'ssl-cert' => \&fix_ssl_client_cert },
++ { 'ssl-key' => \&fix_ssl_client_key },
++ { 'skip-ssl' => \&fix_skip_ssl },
++);
++
++
++#
++# Rules to run for [mysqlbinlog] section
++#  - will be run in order listed here
++#
++my @mysqlbinlog_rules=
++(
++ { 'character-sets-dir' => \&fix_charset_dir },
++);
++
++
++#
++# Rules to run for [mysql_upgrade] section
++#  - will be run in order listed here
++#
++my @mysql_upgrade_rules=
++(
++ { 'tmpdir' => sub { return shift->{ARGS}->{tmpdir}; } },
++);
++
++
++#
++# Generate a [client.<suffix>] group to be
++# used for connecting to [mysqld.<suffix>]
++#
++sub post_check_client_group {
++  my ($self, $config, $client_group_name, $mysqld_group_name)= @_;
++
++
++  #  Settings needed for client, copied from its "mysqld"
++  my %client_needs=
++    (
++     port       => 'port',
++     socket     => 'socket',
++     host       => '#host',
++     user       => '#user',
++     password   => '#password',
++    );
++  my $group_to_copy_from= $config->group($mysqld_group_name);
++  while (my ($name_to, $name_from)= each( %client_needs )) {
++    my $option= $group_to_copy_from->option($name_from);
++
++    if (! defined $option){
++      #print $config;
++      croak "Could not get value for '$name_from' for test $self->{testname}";
++    }
++    $config->insert($client_group_name, $name_to, $option->value())
++  }
++  
++  if (IS_WINDOWS)
++  {
++    if (! $self->{ARGS}->{embedded})
++    {
++      # Shared memory base may or may not be defined (e.g not defined in embedded)
++      my $shm = $group_to_copy_from->option("shared-memory-base-name");
++      if (defined $shm)
++      {
++        $config->insert($client_group_name,"shared-memory-base-name", $shm->value());
++      }
++    }
++  }
++}
++
++
++sub post_check_client_groups {
++ my ($self, $config)= @_;
++
++ my $first_mysqld= $config->first_like('mysqld\.');
++
++ return unless $first_mysqld;
++
++ # Always generate [client] pointing to the first
++ # [mysqld.<suffix>]
++ $self->post_check_client_group($config,
++                              'client',
++                              $first_mysqld->name());
++
++ # Then generate [client.<suffix>] for each [mysqld.<suffix>]
++ foreach my $mysqld ( $config->like('mysqld.') ) {
++   $self->post_check_client_group($config,
++                                'client'.$mysqld->after('mysqld'),
++                                $mysqld->name())
++ }
++
++}
++
++
++#
++# Generate [embedded] by copying the values
++# needed from the default [mysqld] section
++# and from first [mysqld.<suffix>]
++#
++sub post_check_embedded_group {
++  my ($self, $config)= @_;
++
++  return unless $self->{ARGS}->{embedded};
++
++  my $mysqld= $config->group('mysqld') or
++    croak "Can't run with embedded, config has no default mysqld section";
++
++  my $first_mysqld= $config->first_like('mysqld.') or
++    croak "Can't run with embedded, config has no mysqld";
++
++  my %no_copy = map { $_ => 1 }
++    (
++     '#log-error', # Embedded server writes stderr to mysqltest's log file
++     'slave-net-timeout', # Embedded server are not build with replication
++     'shared-memory-base-name', # No shared memory for embedded
++    );
++
++  foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
++    # Don't copy options whose name is in "no_copy" list
++    next if $no_copy{$option->name()};
++
++    $config->insert('embedded', $option->name(), $option->value())
++  }
++
++}
++
++
++sub resolve_at_variable {
++  my ($self, $config, $group, $option)= @_;
++  local $_ = $option->value();
++  my ($res, $after);
++
++  while (m/(.*?)\@((?:\w+\.)+)(#?[-\w]+)/g) {
++    my ($before, $group_name, $option_name)= ($1, $2, $3);
++    $after = $';
++    chop($group_name);
++
++  my $from_group= $config->group($group_name)
++    or croak "There is no group named '$group_name' that ",
++      "can be used to resolve '$option_name' for test '$self->{testname}'";
++
++    my $value= $from_group->value($option_name);
++    $res .= $before.$value;
++  }
++  $res .= $after;
++
++  $config->insert($group->name(), $option->name(), $res)
++}
++
++
++sub post_fix_resolve_at_variables {
++  my ($self, $config)= @_;
++
++  foreach my $group ( $config->groups() ) {
++    foreach my $option ( $group->options()) {
++      next unless defined $option->value();
++
++      $self->resolve_at_variable($config, $group, $option)
++      if ($option->value() =~ /\@/);
++    }
++  }
++}
++
++sub post_fix_mysql_cluster_section {
++  my ($self, $config)= @_;
++
++  # Add a [mysl_cluster.<suffix>] section for each
++  # defined [cluster_config.<suffix>] section
++  foreach my $group ( $config->like('cluster_config\.\w*$') )
++  {
++    my @urls;
++    # Generate ndb_connectstring for this cluster
++    foreach my $ndb_mgmd ( $config->like('cluster_config.ndb_mgmd.')) {
++      if ($ndb_mgmd->suffix() eq $group->suffix()) {
++      my $host= $ndb_mgmd->value('HostName');
++      my $port= $ndb_mgmd->value('PortNumber');
++      push(@urls, "$host:$port");
++      }
++    }
++    croak "Could not generate valid ndb_connectstring for '$group'"
++      unless @urls > 0;
++    my $ndb_connectstring= join(";", @urls);
++
++    # Add ndb_connectstring to [mysql_cluster.<suffix>]
++    $config->insert('mysql_cluster'.$group->suffix(),
++                  'ndb_connectstring', $ndb_connectstring);
++
++    # Add ndb_connectstring to each mysqld connected to this
++    # cluster
++    foreach my $mysqld ( $config->like('cluster_config.mysqld.')) {
++      if ($mysqld->suffix() eq $group->suffix()) {
++      my $after= $mysqld->after('cluster_config.mysqld');
++      $config->insert("mysqld$after",
++                      'ndb_connectstring', $ndb_connectstring);
++      }
++    }
++  }
++}
++
++#
++# Rules to run last of all
++#
++my @post_rules=
++(
++ \&post_check_client_groups,
++ \&post_fix_mysql_cluster_section,
++ \&post_fix_resolve_at_variables,
++ \&post_check_embedded_group,
++);
++
++
++sub run_rules_for_group {
++  my ($self, $config, $group, @rules)= @_;
++  foreach my $hash ( @rules ) {
++    while (my ($option, $rule)= each( %{$hash} )) {
++      # Only run this rule if the value is not already defined
++      if (!$config->exists($group->name(), $option)) {
++      my $value;
++      if (ref $rule eq "CODE") {
++        # Call the rule function
++        $value= &$rule($self, $config, $group->name(),
++                       $config->group($group->name()));
++      } else {
++        $value= $rule;
++      }
++      if (defined $value) {
++        $config->insert($group->name(), $option, $value, 1);
++      }
++      }
++    }
++  }
++}
++
++
++sub run_section_rules {
++  my ($self, $config, $name, @rules)= @_;
++
++  foreach my $group ( $config->like($name) ) {
++    $self->run_rules_for_group($config, $group, @rules);
++  }
++}
++
++
++sub run_generate_sections_from_cluster_config {
++  my ($self, $config)= @_;
++
++  my @options= ('ndb_mgmd', 'ndbd',
++              'mysqld', 'ndbapi');
++
++  foreach my $group ( $config->like('cluster_config\.\w*$') ) {
++
++    # Keep track of current index per process type
++    my %idxes;
++    map { $idxes{$_}= 1; } @options;
++
++    foreach my $option_name ( @options ) {
++      my $value= $group->value($option_name);
++      my @hosts= split(/,/, $value, -1); # -1 => return also empty strings
++
++      # Add at least one host
++      push(@hosts, undef) unless scalar(@hosts);
++
++      # Assign hosts unless already fixed
++      @hosts= map { $self->fix_host() unless $_; } @hosts;
++
++      # Write the hosts value back
++      $group->insert($option_name, join(",", @hosts));
++
++      # Generate sections for each host
++      foreach my $host ( @hosts ){
++      my $idx= $idxes{$option_name}++;
++
++      my $suffix= $group->suffix();
++      # Generate a section for ndb_mgmd to read
++      $config->insert("cluster_config.$option_name.$idx$suffix",
++                      "HostName", $host);
++
++      if ($option_name eq 'mysqld'){
++        my $datadir=
++          $self->fix_cluster_dir($config,
++                                 "cluster_config.mysqld.$idx$suffix",
++                                 $group);
++        $config->insert("mysqld.$idx$suffix",
++                        'datadir', "$datadir/data");
++      }
++      }
++    }
++  }
++}
++
++
++sub new_config {
++  my ($class, $args)= @_;
++
++  my @required_args= ('basedir', 'baseport', 'vardir', 'template_path');
++
++  foreach my $required ( @required_args ) {
++    croak "you must pass '$required'" unless defined $args->{$required};
++  }
++
++  # Open the config template
++  my $config= My::Config->new($args->{'template_path'});
++  my $self= bless {
++                 CONFIG       => $config,
++                 ARGS         => $args,
++                 PORT         => $args->{baseport},
++                 SERVER_ID    => 1,
++                   testname     => $args->{testname},
++                }, $class;
++
++  # Run pre rules
++  foreach my $rule ( @pre_rules ) {
++    &$rule($self, $config);
++  }
++
++  $self->run_section_rules($config,
++                         'cluster_config\.\w*$',
++                         @cluster_config_rules);
++  $self->run_generate_sections_from_cluster_config($config);
++
++  $self->run_section_rules($config,
++                         'cluster_config.ndb_mgmd.',
++                         @ndb_mgmd_rules);
++  $self->run_section_rules($config,
++                         'cluster_config.ndbd',
++                         @ndbd_rules);
++
++  $self->run_section_rules($config,
++                         'mysqld.',
++                         @mysqld_rules);
++
++  $self->run_section_rules($config,
++                          'memcached.',
++                          @memcached_rules);
++
++  # [mysqlbinlog] need additional settings
++  $self->run_rules_for_group($config,
++                           $config->insert('mysqlbinlog'),
++                           @mysqlbinlog_rules);
++
++  # [mysql_upgrade] need additional settings
++  $self->run_rules_for_group($config,
++                           $config->insert('mysql_upgrade'),
++                           @mysql_upgrade_rules);
++
++  # Additional rules required for [client]
++  $self->run_rules_for_group($config,
++                           $config->insert('client'),
++                           @client_rules);
++
++
++  # Additional rules required for [mysqltest]
++  $self->run_rules_for_group($config,
++                           $config->insert('mysqltest'),
++                           @mysqltest_rules);
++
++  {
++    # Run post rules
++    foreach my $rule ( @post_rules ) {
++      &$rule($self, $config);
++    }
++  }
++
++  return $config;
++}
++
++
++1;
++
+diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm
+index eed3100..d3a36e8 100644
+--- a/mysql-test/lib/mtr_cases.pm
++++ b/mysql-test/lib/mtr_cases.pm
+@@ -509,6 +509,9 @@ sub collect_one_suite($)
+       my @new_cases;
+       foreach my $comb (@combinations)
+       {
++      # ENV is used in My::Config::ENV to store the environment so is not a true combination
++      next if ( $comb->{'name'} eq 'ENV' );
++
+       foreach my $test (@cases)
+       {
+diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
+index 82b5d1c..da9876a 100755
+--- a/mysql-test/mysql-test-run.pl
++++ b/mysql-test/mysql-test-run.pl
+@@ -360,6 +360,8 @@ sub main {
+     gcov_prepare($basedir);
+   }
++  check_wsrep_support();
++
+   if (!$opt_suites) {
+     $opt_suites= $DEFAULT_SUITES;
+   }
+@@ -2895,7 +2897,6 @@ sub check_ndbcluster_support ($) {
+       # which is the default case
+       return;
+     }
+-
+     if ($opt_skip_ndbcluster)
+     {
+       # Compiled with ndbcluster but ndbcluster skipped
+@@ -3311,6 +3312,49 @@ sub ndbcluster_start ($) {
+ }
++sub have_wsrep() {
++  my $wsrep_on= $mysqld_variables{'wsrep-on'};
++  return defined $wsrep_on
++}
++
++
++sub check_wsrep_support() {
++  if (have_wsrep())
++  {
++    mtr_report(" - binaries built with wsrep patch");
++
++    # ADD scripts to $PATH to that wsrep_sst_* can be found
++    my ($path) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
++    mtr_error("No SST scripts") unless $path;
++    $ENV{PATH}="$path:$ENV{PATH}";
++
++    # Check whether WSREP_PROVIDER environment variable is set.
++    if (defined $ENV{'WSREP_PROVIDER'}) {
++      if ((mtr_file_exists($ENV{'WSREP_PROVIDER'}) eq "")  &&
++          ($ENV{'WSREP_PROVIDER'} ne "none")) {
++        mtr_error("WSREP_PROVIDER env set to an invalid path");
++      }
++      # WSREP_PROVIDER is valid; set to a valid path or "none").
++      mtr_verbose("WSREP_PROVIDER env set to $ENV{'WSREP_PROVIDER'}");
++    } else {
++      # WSREP_PROVIDER env not defined. Lets try to locate the wsrep provider
++      # library.
++      my $file_wsrep_provider=
++        mtr_file_exists("/usr/lib/galera/libgalera_smm.so",
++                        "/usr/lib64/galera/libgalera_smm.so");
++
++      if ($file_wsrep_provider ne "") {
++        # wsrep provider library found !
++        mtr_verbose("wsrep provider library found : $file_wsrep_provider");
++        $ENV{'WSREP_PROVIDER'}= $file_wsrep_provider;
++      } else {
++        mtr_verbose("Could not find wsrep provider library, setting it to 'none'");
++        $ENV{'WSREP_PROVIDER'}= "none";
++      }
++    }
++  }
++}
++
+ sub create_config_file_for_extern {
+   my %opts=
+     (
+@@ -3737,6 +3781,24 @@ sub run_query {
+ }
++sub sleep_until_returns_true($$$) {
++  my ($tinfo, $mysqld, $query)= @_;
++
++  my $timeout = $opt_start_timeout;
++  my $sleeptime= 100; # Milliseconds
++  my $loops= ($timeout * 1000) / $sleeptime;
++
++  for ( my $loop= 1; $loop <= $loops; $loop++ ) {
++    my $query_result = run_query($tinfo, $mysqld, $query);
++    if (run_query($tinfo, $mysqld, $query) == 1) {
++      return 0;
++    }
++  }
++  
++  return 1;
++}
++
++
+ sub do_before_run_mysqltest($)
+ {
+   my $tinfo= shift;
+@@ -5785,6 +5847,13 @@ sub start_servers($) {
+       }
+       return 1;
+     }
++
++    if (have_wsrep()) {
++      if(sleep_until_returns_true($tinfo, $mysqld, 'SELECT @@wsrep_ready')) {
++         $tinfo->{logfile}= "WSREP did not transition to state READY";
++         return 1;
++      }
++    }
+   }
+   # Start memcached(s) for each cluster
+diff --git a/mysql-test/r/galera_sst_mode.result b/mysql-test/r/galera_sst_mode.result
+new file mode 100644
+index 0000000..ea25b32
+--- /dev/null
++++ b/mysql-test/r/galera_sst_mode.result
+@@ -0,0 +1,24 @@
++#
++# Test for mysqldump's galera-sst-mode option
++#
++#
++# MDEV-6490: mysqldump unknown option --galera-sst-mode
++#
++CREATE DATABASE bug6490;
++USE bug6490;
++CREATE TABLE t1(c1 INT);
++INSERT INTO t1 values (1);
++INSERT INTO t1 values (2);
++# Save the current gtid_binlog_state.
++# Take a dump of bug6490 database
++DROP TABLE t1;
++# Load the dump
++RESET MASTER;
++SELECT * from t1;
++c1
++1
++2
++# Compare the two gtid_binlog_state's
++# Cleanup
++DROP DATABASE bug6490;
++# End of test
+diff --git a/mysql-test/r/have_wsrep.require b/mysql-test/r/have_wsrep.require
+new file mode 100644
+index 0000000..af32ac7
+--- /dev/null
++++ b/mysql-test/r/have_wsrep.require
+@@ -0,0 +1,2 @@
++Variable_name Value
++wsrep_on      ON
+diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
+index fce2f40..149babc 100644
+--- a/mysql-test/r/information_schema.result
++++ b/mysql-test/r/information_schema.result
+@@ -1664,9 +1664,7 @@ drop table if exists t1;drop table if exists t1;
+ drop table if exists t1;drop table if exists t1;
+ drop table if exists t1;drop table if exists t1;
+ drop table if exists t1;drop table if exists t1;
+-drop table if exists t1;drop table if exists
+-Warnings:
+-Warning       1265    Data truncated for column 'VARIABLE_VALUE' at row 1
++drop table if exists t1;drop table if exists t1;
+ set global init_connect="";
+ create table t0 select * from information_schema.global_status where VARIABLE_NAME='COM_SELECT';
+ SELECT 1;
+diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result
+index 18b21ff..d31ef0f 100644
+--- a/mysql-test/r/mysqld--help-notwin.result
++++ b/mysql-test/r/mysqld--help-notwin.result
+@@ -1010,6 +1010,94 @@ The following options may be given as the first argument:
+  -V, --version       Output version information and exit.
+  --wait-timeout=#    The number of seconds the server waits for activity on a
+  connection before closing it
++ --wsrep-OSU-method[=name] 
++ Method for Online Schema Upgrade
++ --wsrep-auto-increment-control 
++ To automatically control the assignment of autoincrement
++ variables
++ (Defaults to on; use --skip-wsrep-auto-increment-control to disable.)
++ --wsrep-causal-reads 
++ (DEPRECATED) setting this variable is equivalent to
++ setting wsrep_sync_wait READ flag
++ --wsrep-certify-nonPK 
++ Certify tables with no primary key
++ (Defaults to on; use --skip-wsrep-certify-nonPK to disable.)
++ --wsrep-cluster-address=name 
++ Address to initially connect to cluster
++ --wsrep-cluster-name=name 
++ Name for the cluster
++ --wsrep-convert-LOCK-to-trx 
++ To convert locking sessions into transactions
++ --wsrep-data-home-dir=name 
++ home directory for wsrep provider
++ --wsrep-dbug-option=name 
++ DBUG options to provider library
++ --wsrep-debug       To enable debug level logging
++ --wsrep-desync      To desynchronize the node from the cluster
++ --wsrep-drupal-282555-workaround 
++ To use a workaround forbad autoincrement value
++ --wsrep-forced-binlog-format=name 
++ binlog format to take effect over user's choice
++ --wsrep-load-data-splitting 
++ To commit LOAD DATA transaction after every 10K rows
++ inserted
++ (Defaults to on; use --skip-wsrep-load-data-splitting to disable.)
++ --wsrep-log-conflicts 
++ To log multi-master conflicts
++ --wsrep-max-ws-rows=# 
++ Max number of rows in write set
++ --wsrep-max-ws-size=# 
++ Max write set size (bytes)
++ --wsrep-mysql-replication-bundle=# 
++ mysql replication group commit 
++ --wsrep-node-address=name 
++ Node address
++ --wsrep-node-incoming-address=name 
++ Client connection address
++ --wsrep-node-name=name 
++ Node name
++ --wsrep-notify-cmd=name 
++ --wsrep-on          To enable wsrep replication 
++ (Defaults to on; use --skip-wsrep-on to disable.)
++ --wsrep-preordered  To enable preordered write set processing
++ --wsrep-provider=name 
++ Path to replication provider library
++ --wsrep-provider-options=name 
++ provider specific options
++ --wsrep-recover     Recover database state after crash and exit
++ --wsrep-replicate-myisam 
++ To enable myisam replication
++ --wsrep-restart-slave 
++ Should MySQL slave be restarted automatically, when node
++ joins back to cluster
++ --wsrep-retry-autocommit=# 
++ Max number of times to retry a failed autocommit
++ statement
++ --wsrep-slave-FK-checks 
++ Should slave thread do foreign key constraint checks
++ (Defaults to on; use --skip-wsrep-slave-FK-checks to disable.)
++ --wsrep-slave-UK-checks 
++ Should slave thread do secondary index uniqueness chesks
++ --wsrep-slave-threads=# 
++ Number of slave appliers to launch
++ --wsrep-sst-auth=name 
++ Authentication for SST connection
++ --wsrep-sst-donor=name 
++ preferred donor node for the SST
++ --wsrep-sst-donor-rejects-queries 
++ Reject client queries when donating state snapshot
++ transfer
++ --wsrep-sst-method=name 
++ State snapshot transfer method
++ --wsrep-sst-receive-address=name 
++ Address where node is waiting for SST contact
++ --wsrep-start-position=name 
++ global transaction position to start from 
++ --wsrep-sync-wait[=#] 
++ Ensure "synchronous" read view before executing an
++ operation of the type specified by bitmask: 1 -
++ READ(includes SELECT, SHOW and BEGIN/START TRANSACTION);
++ 2 - UPDATE and DELETE; 4 - INSERT and REPLACE
+ Variables (--variable-name=value)
+ abort-slave-event-count 0
+@@ -1299,6 +1387,45 @@ updatable-views-with-limit YES
+ validate-user-plugins TRUE
+ verbose TRUE
+ wait-timeout 28800
++wsrep-OSU-method TOI
++wsrep-auto-increment-control TRUE
++wsrep-causal-reads FALSE
++wsrep-certify-nonPK TRUE
++wsrep-cluster-address 
++wsrep-cluster-name my_wsrep_cluster
++wsrep-convert-LOCK-to-trx FALSE
++wsrep-data-home-dir 
++wsrep-dbug-option 
++wsrep-debug FALSE
++wsrep-desync FALSE
++wsrep-drupal-282555-workaround FALSE
++wsrep-forced-binlog-format NONE
++wsrep-load-data-splitting TRUE
++wsrep-log-conflicts FALSE
++wsrep-max-ws-rows 131072
++wsrep-max-ws-size 1073741824
++wsrep-mysql-replication-bundle 0
++wsrep-node-address 
++wsrep-node-incoming-address AUTO
++wsrep-notify-cmd 
++wsrep-on FALSE
++wsrep-preordered FALSE
++wsrep-provider none
++wsrep-provider-options 
++wsrep-recover FALSE
++wsrep-replicate-myisam FALSE
++wsrep-restart-slave FALSE
++wsrep-retry-autocommit 1
++wsrep-slave-FK-checks TRUE
++wsrep-slave-UK-checks FALSE
++wsrep-slave-threads 1
++wsrep-sst-auth (No default value)
++wsrep-sst-donor 
++wsrep-sst-donor-rejects-queries FALSE
++wsrep-sst-method rsync
++wsrep-sst-receive-address AUTO
++wsrep-start-position 00000000-0000-0000-0000-000000000000:-1
++wsrep-sync-wait 0
+ To see what values a running MySQL server is using, type
+ 'mysqladmin variables' instead of 'mysqld --verbose --help'.
+diff --git a/mysql-test/r/not_wsrep.require b/mysql-test/r/not_wsrep.require
+new file mode 100644
+index 0000000..7c8e74a
+--- /dev/null
++++ b/mysql-test/r/not_wsrep.require
+@@ -0,0 +1,2 @@
++HAVE_WSREP
++0
+diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
+index 92d3147..8bc7b0e 100644
+--- a/mysql-test/r/show_check.result
++++ b/mysql-test/r/show_check.result
+@@ -101,19 +101,19 @@ drop table t1;
+ show variables like "wait_timeout%";
+ Catalog       Database        Table   Table_alias     Column  Column_alias    Type    Length  Max length      Is_null Flags   Decimals        Charsetnr
+ def   information_schema      VARIABLES       VARIABLES       VARIABLE_NAME   Variable_name   253     64      12      N       1       0       8
+-def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     1024    5       Y       0       0       8
++def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     2048    5       Y       0       0       8
+ Variable_name Value
+ wait_timeout  28800
+ show variables like "WAIT_timeout%";
+ Catalog       Database        Table   Table_alias     Column  Column_alias    Type    Length  Max length      Is_null Flags   Decimals        Charsetnr
+ def   information_schema      VARIABLES       VARIABLES       VARIABLE_NAME   Variable_name   253     64      12      N       1       0       8
+-def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     1024    5       Y       0       0       8
++def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     2048    5       Y       0       0       8
+ Variable_name Value
+ wait_timeout  28800
+ show variables like "this_doesn't_exists%";
+ Catalog       Database        Table   Table_alias     Column  Column_alias    Type    Length  Max length      Is_null Flags   Decimals        Charsetnr
+ def   information_schema      VARIABLES       VARIABLES       VARIABLE_NAME   Variable_name   253     64      0       N       1       0       8
+-def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     1024    0       Y       0       0       8
++def   information_schema      VARIABLES       VARIABLES       VARIABLE_VALUE  Value   253     2048    0       Y       0       0       8
+ Variable_name Value
+ show table status from test like "this_doesn't_exists%";
+ Catalog       Database        Table   Table_alias     Column  Column_alias    Type    Length  Max length      Is_null Flags   Decimals        Charsetnr
+diff --git a/mysql-test/std_data/wsrep_notify.sh b/mysql-test/std_data/wsrep_notify.sh
+new file mode 100644
+index 0000000..7036f60
+--- /dev/null
++++ b/mysql-test/std_data/wsrep_notify.sh
+@@ -0,0 +1,99 @@
++#!/bin/sh -eu
++
++# This is a simple example of wsrep notification script (wsrep_notify_cmd).
++# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status'
++# and fill them on every membership or node status change.
++#
++# Edit parameters below to specify the address and login to server.
++
++USER=root
++HOST=127.0.0.1
++PORT=$NODE_MYPORT_1
++
++SCHEMA="mtr_wsrep_notify"
++MEMB_TABLE="$SCHEMA.membership"
++STATUS_TABLE="$SCHEMA.status"
++
++BEGIN="
++SET wsrep_on=0;
++CREATE SCHEMA IF NOT EXISTS $SCHEMA;
++CREATE TABLE IF NOT EXISTS $MEMB_TABLE (
++    idx  INT,
++    uuid CHAR(40), /* node UUID */
++    name VARCHAR(32),     /* node name */
++    addr VARCHAR(256)     /* node address */
++) ENGINE=MEMORY;
++CREATE TABLE IF NOT EXISTS $STATUS_TABLE (
++    size   INT,      /* component size   */
++    idx    INT,      /* this node index  */
++    status CHAR(16), /* this node status */
++    uuid   CHAR(40), /* cluster UUID */
++    prim   BOOLEAN   /* if component is primary */
++) ENGINE=MEMORY;
++BEGIN;
++"
++END="COMMIT;"
++
++configuration_change()
++{
++    echo "$BEGIN;"
++
++    local idx=0
++
++    for NODE in $(echo $MEMBERS | sed s/,/\ /g)
++    do
++        echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, "
++        # Don't forget to properly quote string values
++        echo "'$NODE'" | sed  s/\\//\',\'/g
++        echo ");"
++        idx=$(( $idx + 1 ))
++    done
++
++    echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);"
++
++    echo "$END"
++}
++
++status_update()
++{
++    echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;"
++}
++
++COM=status_update # not a configuration change by default
++
++while [ $# -gt 0 ]
++do
++    case $1 in
++    --status)
++        STATUS=$2
++        shift
++        ;;
++    --uuid)
++        CLUSTER_UUID=$2
++        shift
++        ;;
++    --primary)
++        [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0"
++        COM=configuration_change
++        shift
++        ;;
++    --index)
++        INDEX=$2
++        shift
++        ;;
++    --members)
++        MEMBERS=$2
++        shift
++        ;;
++    esac
++    shift
++done
++
++# Undefined means node is shutting down
++if [ "$STATUS" != "Undefined" ]
++then
++    $COM | mysql -B -u$USER -h$HOST -P$PORT
++fi
++
++exit 0
++#
+diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result
+index f60f80c..142a522 100644
+--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result
++++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result
+@@ -788,9 +788,11 @@ SELECT * FROM t1;
+ c1
+ 1
+ # Their values should be ON
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    ON
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks ON
+ SET @@SESSION.foreign_key_checks= OFF;
+@@ -806,9 +808,11 @@ c1
+ 1
+ 2
+ # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    OFF
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks OFF
+ # INSERT INTO t1 VALUES(2)
+ # foreign_key_checks=1 and unique_checks=1
+@@ -824,8 +828,10 @@ c1
+ 1
+ 2
+ # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    OFF
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks OFF
+ DROP TABLE t1;
+diff --git a/mysql-test/suite/binlog/r/binlog_simplified_binlog_gtid_recovery.result b/mysql-test/suite/binlog/r/binlog_simplified_binlog_gtid_recovery.result
+new file mode 100644
+index 0000000..40b50b8
+--- /dev/null
++++ b/mysql-test/suite/binlog/r/binlog_simplified_binlog_gtid_recovery.result
+@@ -0,0 +1,47 @@
++include/rpl_init.inc [topology=none]
++include/rpl_default_connections.inc
++CREATE TABLE t1 (
++c1 INT NOT NULL PRIMARY KEY
++);
++# Generate master-bin.000002
++FLUSH LOGS;
++INSERT INTO t1 VALUES (1);
++# Generate master-bin.000003
++FLUSH LOGS;
++INSERT INTO t1 VALUES (2);
++# Generate master-bin.000004
++FLUSH LOGS;
++INSERT INTO t1 VALUES (3);
++# Move master-bin.000002 to master-bin.000002.bkp and
++# master-bin.000003 to master-bin.000003.bkp
++#
++# Only master-bin.000001 and master-bin.000004 remain, others are moved
++# , restart the server with enabled simplified-binlog-gtid-recovery
++# and gtid_mode on. If the server scans more than one binary log in
++# every iteration, it will cause read error on the 2nd and 3rd files.
++#
++include/rpl_restart_server.inc [server_number=1 parameters: --simplified-binlog-gtid-recovery=on --gtid-mode=on --enforce-gtid-consistency --log-slave-updates]
++#
++# Verify that GLOBAL.GTID_EXECUTED and GLOBAL.GTID_PURGED are empty
++# after server restarts.
++#
++include/assert.inc [GLOBAL.GTID_EXECUTED must be empty.]
++include/assert.inc [GLOBAL.GTID_PURGED must be empty.]
++DROP TABLE t1;
++# Move master-bin.000004 to master-bin.000004.bkp
++#
++# Only master-bin.000001 and master-bin.000005 remain, others are moved
++# , restart the server with enabled simplified-binlog-gtid-recovery
++# and gtid_mode on again. If the server scans more than one binary
++# log in every iteration, it will cause read error on the 2nd and
++# 4th files.
++#
++include/rpl_restart_server.inc [server_number=1 parameters: --simplified-binlog-gtid-recovery=on --gtid-mode=on --enforce-gtid-consistency --log-slave-updates]
++#
++# Verify that GLOBAL.GTID_EXECUTED contains committed gtid MASTER_UUID:1
++# and GLOBAL.GTID_PURGED is empty after server restarts again.
++#
++include/assert.inc [committed gtid MASTER_UUID:1]
++include/assert.inc [GLOBAL.GTID_PURGED is empty]
++# Move binary logs back.
++include/rpl_end.inc
+diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+index e0cc9ca..8842ace 100644
+--- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result
++++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+@@ -557,9 +557,11 @@ SELECT * FROM t1;
+ c1
+ 1
+ # Their values should be ON
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    ON
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks ON
+ SET @@SESSION.foreign_key_checks= OFF;
+@@ -575,9 +577,11 @@ c1
+ 1
+ 2
+ # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    OFF
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks OFF
+ # INSERT INTO t1 VALUES(2)
+ # foreign_key_checks=1 and unique_checks=1
+@@ -593,8 +597,10 @@ c1
+ 1
+ 2
+ # Their values should be OFF
+-SHOW SESSION VARIABLES LIKE "%_checks";
++SHOW SESSION VARIABLES LIKE "foreign_key_checks";
+ Variable_name Value
+ foreign_key_checks    OFF
++SHOW SESSION VARIABLES LIKE "unique_checks";
++Variable_name Value
+ unique_checks OFF
+ DROP TABLE t1;
+diff --git a/mysql-test/suite/binlog/t/binlog_simplified_binlog_gtid_recovery.test b/mysql-test/suite/binlog/t/binlog_simplified_binlog_gtid_recovery.test
+new file mode 100644
+index 0000000..5337e7b
+--- /dev/null
++++ b/mysql-test/suite/binlog/t/binlog_simplified_binlog_gtid_recovery.test
+@@ -0,0 +1,120 @@
++# ==== Purpose ====
++#
++# BUG#16741603: MYSQLD SCANS ALL BINARY LOGS ON CRASH RECOVERY
++#
++# Verify that the server does not scan more than one binary log
++# in every iteration when initializing GTID sets on server start
++# if simplified-binlog-gtid-recovery is enabled.
++#
++#
++# ==== Implementation ====
++#
++# 1) Start server and generate four binary logs with gtid_mode off.
++# 2) Move master-bin.000002 to master-bin.000002.bkp and
++#    master-bin.000003 to master-bin.000003.bkp
++# 3) Only master-bin.000001 and master-bin.000004 remain, others are moved
++#    , restart the server with enabled simplified-binlog-gtid-recovery
++#    and gtid_mode on. If the server scans more than one binary log in
++#    every iteration, it will cause read error on the 2nd and 3rd files.
++# 4) Verify that GLOBAL.GTID_EXECUTED and GLOBAL.GTID_PURGED are empty
++#    after server restarts.
++# 5) Move master-bin.000004 to master-bin.000004.bkp
++# 6) Only master-bin.000001 and master-bin.000005 remain, others are moved
++#    , restart the server with enabled simplified-binlog-gtid-recovery
++#    and gtid_mode on again. If the server scans more than one binary
++#    log in every iteration, it will cause read error on the 2nd and
++#    4th files.
++# 7) Verify that GLOBAL.GTID_EXECUTED contains committed gtid MASTER_UUID:1
++#    and GLOBAL.GTID_PURGED is empty after server restarts again.
++# 8) Move binary logs back.
++#
++
++--source include/not_gtid_enabled.inc
++
++# Invoke rpl_init.inc in order to set up the connections needed by
++# rpl_restart_server.inc
++--let $rpl_server_count= 1
++--let $rpl_topology= none
++--source include/rpl_init.inc
++--source include/rpl_default_connections.inc
++
++--let $MYSQLD_DATADIR= `select @@datadir`
++--let $master_uuid= `SELECT @@GLOBAL.SERVER_UUID`
++CREATE TABLE t1 (
++  c1 INT NOT NULL PRIMARY KEY
++);
++
++--echo # Generate master-bin.000002
++FLUSH LOGS;
++INSERT INTO t1 VALUES (1);
++--let $binlog_file2= query_get_value(SHOW MASTER STATUS, File, 1)
++
++--echo # Generate master-bin.000003
++FLUSH LOGS;
++INSERT INTO t1 VALUES (2);
++--let $binlog_file3= query_get_value(SHOW MASTER STATUS, File, 1)
++
++--echo # Generate master-bin.000004
++FLUSH LOGS;
++INSERT INTO t1 VALUES (3);
++--let $binlog_file4= query_get_value(SHOW MASTER STATUS, File, 1)
++
++--echo # Move master-bin.000002 to master-bin.000002.bkp and
++--echo # master-bin.000003 to master-bin.000003.bkp
++--move_file $MYSQLD_DATADIR/$binlog_file2 $MYSQLD_DATADIR/$binlog_file2.bkp
++--move_file $MYSQLD_DATADIR/$binlog_file3 $MYSQLD_DATADIR/$binlog_file3.bkp
++
++--echo #
++--echo # Only master-bin.000001 and master-bin.000004 remain, others are moved
++--echo # , restart the server with enabled simplified-binlog-gtid-recovery
++--echo # and gtid_mode on. If the server scans more than one binary log in
++--echo # every iteration, it will cause read error on the 2nd and 3rd files.
++--echo #
++--let $rpl_server_number= 1
++--let $rpl_server_parameters= --simplified-binlog-gtid-recovery=on --gtid-mode=on --enforce-gtid-consistency --log-slave-updates
++--source include/rpl_restart_server.inc
++
++--echo #
++--echo # Verify that GLOBAL.GTID_EXECUTED and GLOBAL.GTID_PURGED are empty
++--echo # after server restarts.
++--echo #
++--let $assert_text= GLOBAL.GTID_EXECUTED must be empty.
++--let $assert_cond= "[SELECT @@GLOBAL.GTID_EXECUTED]" = ""
++--source include/assert.inc
++--let $assert_text= GLOBAL.GTID_PURGED must be empty.
++--let $assert_cond= "[SELECT @@GLOBAL.GTID_PURGED]" = ""
++--source include/assert.inc
++
++DROP TABLE t1;
++--echo # Move master-bin.000004 to master-bin.000004.bkp
++--move_file $MYSQLD_DATADIR/$binlog_file4 $MYSQLD_DATADIR/$binlog_file4.bkp
++
++--echo #
++--echo # Only master-bin.000001 and master-bin.000005 remain, others are moved
++--echo # , restart the server with enabled simplified-binlog-gtid-recovery
++--echo # and gtid_mode on again. If the server scans more than one binary
++--echo # log in every iteration, it will cause read error on the 2nd and
++--echo # 4th files.
++--echo #
++--let $rpl_server_number= 1
++--let $rpl_server_parameters= --simplified-binlog-gtid-recovery=on --gtid-mode=on --enforce-gtid-consistency --log-slave-updates
++--source include/rpl_restart_server.inc
++
++--echo #
++--echo # Verify that GLOBAL.GTID_EXECUTED contains committed gtid MASTER_UUID:1
++--echo # and GLOBAL.GTID_PURGED is empty after server restarts again.
++--echo #
++--let $assert_text= committed gtid MASTER_UUID:1
++--let $assert_cond= "[SELECT @@GLOBAL.GTID_EXECUTED]" = "$master_uuid:1"
++--source include/assert.inc
++--let $assert_text= GLOBAL.GTID_PURGED is empty
++--let $assert_cond= "[SELECT @@GLOBAL.GTID_PURGED]" = ""
++--source include/assert.inc
++
++--echo # Move binary logs back.
++--move_file $MYSQLD_DATADIR/$binlog_file2.bkp $MYSQLD_DATADIR/$binlog_file2
++--move_file $MYSQLD_DATADIR/$binlog_file3.bkp $MYSQLD_DATADIR/$binlog_file3
++--move_file $MYSQLD_DATADIR/$binlog_file4.bkp $MYSQLD_DATADIR/$binlog_file4
++
++--source include/rpl_end.inc
++
+diff --git a/mysql-test/suite/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result
+index f0ab3a7..ec485d4 100644
+--- a/mysql-test/suite/funcs_1/r/is_columns_is.result
++++ b/mysql-test/suite/funcs_1/r/is_columns_is.result
+@@ -111,9 +111,9 @@ def        information_schema      FILES   UPDATE_COUNT    13      NULL    YES     bigint  NULL    NULL    19      0       NULL
+ def   information_schema      FILES   UPDATE_TIME     34      NULL    YES     datetime        NULL    NULL    NULL    NULL    0       NULL    NULL    datetime                        select  
+ def   information_schema      FILES   VERSION 25      NULL    YES     bigint  NULL    NULL    20      0       NULL    NULL    NULL    bigint(21) unsigned                     select  
+ def   information_schema      GLOBAL_STATUS   VARIABLE_NAME   1               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+-def   information_schema      GLOBAL_STATUS   VARIABLE_VALUE  2       NULL    YES     varchar 1024    3072    NULL    NULL    NULL    utf8    utf8_general_ci varchar(1024)                   select  
++def   information_schema      GLOBAL_STATUS   VARIABLE_VALUE  2       NULL    YES     varchar 2048    6144    NULL    NULL    NULL    utf8    utf8_general_ci varchar(2048)                   select  
+ def   information_schema      GLOBAL_VARIABLES        VARIABLE_NAME   1               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+-def   information_schema      GLOBAL_VARIABLES        VARIABLE_VALUE  2       NULL    YES     varchar 1024    3072    NULL    NULL    NULL    utf8    utf8_general_ci varchar(1024)                   select  
++def   information_schema      GLOBAL_VARIABLES        VARIABLE_VALUE  2       NULL    YES     varchar 2048    6144    NULL    NULL    NULL    utf8    utf8_general_ci varchar(2048)                   select  
+ def   information_schema      KEY_COLUMN_USAGE        COLUMN_NAME     7               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+ def   information_schema      KEY_COLUMN_USAGE        CONSTRAINT_CATALOG      1               NO      varchar 512     1536    NULL    NULL    NULL    utf8    utf8_general_ci varchar(512)                    select  
+ def   information_schema      KEY_COLUMN_USAGE        CONSTRAINT_NAME 3               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+@@ -243,9 +243,9 @@ def        information_schema      SCHEMA_PRIVILEGES       PRIVILEGE_TYPE  4               NO      varchar 64      192     NUL
+ def   information_schema      SCHEMA_PRIVILEGES       TABLE_CATALOG   2               NO      varchar 512     1536    NULL    NULL    NULL    utf8    utf8_general_ci varchar(512)                    select  
+ def   information_schema      SCHEMA_PRIVILEGES       TABLE_SCHEMA    3               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+ def   information_schema      SESSION_STATUS  VARIABLE_NAME   1               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+-def   information_schema      SESSION_STATUS  VARIABLE_VALUE  2       NULL    YES     varchar 1024    3072    NULL    NULL    NULL    utf8    utf8_general_ci varchar(1024)                   select  
++def   information_schema      SESSION_STATUS  VARIABLE_VALUE  2       NULL    YES     varchar 2048    6144    NULL    NULL    NULL    utf8    utf8_general_ci varchar(2048)                   select  
+ def   information_schema      SESSION_VARIABLES       VARIABLE_NAME   1               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+-def   information_schema      SESSION_VARIABLES       VARIABLE_VALUE  2       NULL    YES     varchar 1024    3072    NULL    NULL    NULL    utf8    utf8_general_ci varchar(1024)                   select  
++def   information_schema      SESSION_VARIABLES       VARIABLE_VALUE  2       NULL    YES     varchar 2048    6144    NULL    NULL    NULL    utf8    utf8_general_ci varchar(2048)                   select  
+ def   information_schema      STATISTICS      CARDINALITY     10      NULL    YES     bigint  NULL    NULL    19      0       NULL    NULL    NULL    bigint(21)                      select  
+ def   information_schema      STATISTICS      COLLATION       9       NULL    YES     varchar 1       3       NULL    NULL    NULL    utf8    utf8_general_ci varchar(1)                      select  
+ def   information_schema      STATISTICS      COLUMN_NAME     8               NO      varchar 64      192     NULL    NULL    NULL    utf8    utf8_general_ci varchar(64)                     select  
+@@ -507,9 +507,9 @@ NULL       information_schema      FILES   CHECKSUM        bigint  NULL    NULL    NULL    NULL    bigint(21) uns
+ 3.0000        information_schema      FILES   STATUS  varchar 20      60      utf8    utf8_general_ci varchar(20)
+ 3.0000        information_schema      FILES   EXTRA   varchar 255     765     utf8    utf8_general_ci varchar(255)
+ 3.0000        information_schema      GLOBAL_STATUS   VARIABLE_NAME   varchar 64      192     utf8    utf8_general_ci varchar(64)
+-3.0000        information_schema      GLOBAL_STATUS   VARIABLE_VALUE  varchar 1024    3072    utf8    utf8_general_ci varchar(1024)
++3.0000        information_schema      GLOBAL_STATUS   VARIABLE_VALUE  varchar 2048    6144    utf8    utf8_general_ci varchar(2048)
+ 3.0000        information_schema      GLOBAL_VARIABLES        VARIABLE_NAME   varchar 64      192     utf8    utf8_general_ci varchar(64)
+-3.0000        information_schema      GLOBAL_VARIABLES        VARIABLE_VALUE  varchar 1024    3072    utf8    utf8_general_ci varchar(1024)
++3.0000        information_schema      GLOBAL_VARIABLES        VARIABLE_VALUE  varchar 2048    6144    utf8    utf8_general_ci varchar(2048)
+ 3.0000        information_schema      KEY_COLUMN_USAGE        CONSTRAINT_CATALOG      varchar 512     1536    utf8    utf8_general_ci varchar(512)
+ 3.0000        information_schema      KEY_COLUMN_USAGE        CONSTRAINT_SCHEMA       varchar 64      192     utf8    utf8_general_ci varchar(64)
+ 3.0000        information_schema      KEY_COLUMN_USAGE        CONSTRAINT_NAME varchar 64      192     utf8    utf8_general_ci varchar(64)
+@@ -639,9 +639,9 @@ NULL       information_schema      ROUTINES        LAST_ALTERED    datetime        NULL    NULL    NULL    NULL    datet
+ 3.0000        information_schema      SCHEMA_PRIVILEGES       PRIVILEGE_TYPE  varchar 64      192     utf8    utf8_general_ci varchar(64)
+ 3.0000        information_schema      SCHEMA_PRIVILEGES       IS_GRANTABLE    varchar 3       9       utf8    utf8_general_ci varchar(3)
+ 3.0000        information_schema      SESSION_STATUS  VARIABLE_NAME   varchar 64      192     utf8    utf8_general_ci varchar(64)
+-3.0000        information_schema      SESSION_STATUS  VARIABLE_VALUE  varchar 1024    3072    utf8    utf8_general_ci varchar(1024)
++3.0000        information_schema      SESSION_STATUS  VARIABLE_VALUE  varchar 2048    6144    utf8    utf8_general_ci varchar(2048)
+ 3.0000        information_schema      SESSION_VARIABLES       VARIABLE_NAME   varchar 64      192     utf8    utf8_general_ci varchar(64)
+-3.0000        information_schema      SESSION_VARIABLES       VARIABLE_VALUE  varchar 1024    3072    utf8    utf8_general_ci varchar(1024)
++3.0000        information_schema      SESSION_VARIABLES       VARIABLE_VALUE  varchar 2048    6144    utf8    utf8_general_ci varchar(2048)
+ 3.0000        information_schema      STATISTICS      TABLE_CATALOG   varchar 512     1536    utf8    utf8_general_ci varchar(512)
+ 3.0000        information_schema      STATISTICS      TABLE_SCHEMA    varchar 64      192     utf8    utf8_general_ci varchar(64)
+ 3.0000        information_schema      STATISTICS      TABLE_NAME      varchar 64      192     utf8    utf8_general_ci varchar(64)
+diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf
+new file mode 100644
+index 0000000..8adae4c
+--- /dev/null
++++ b/mysql-test/suite/galera/galera_2nodes.cnf
+@@ -0,0 +1,55 @@
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.1.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[mysqld.2]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
+diff --git a/mysql-test/suite/galera/galera_2nodes_as_master.cnf b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
+new file mode 100644
+index 0000000..614ece9
+--- /dev/null
++++ b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
+@@ -0,0 +1,71 @@
++#
++# This .cnf file creates a setup with a 2-node Galera cluster and one stand-alone MySQL server, to be used as a slave
++#
++
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++server-id=1
++binlog-format=row
++log-bin=mysqld-bin
++log_slave_updates
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.1.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[mysqld.2]
++server-id=2
++binlog-format=row
++log-bin=mysqld-bin
++log_slave_updates
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[mysqld.3]
++server-id=3
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_MYPORT_3= @mysqld.3.port
++NODE_MYSOCK_3= @mysqld.3.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
+diff --git a/mysql-test/suite/galera/galera_2nodes_as_slave.cnf b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
+new file mode 100644
+index 0000000..5d14109
+--- /dev/null
++++ b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
+@@ -0,0 +1,68 @@
++#
++# This .cnf file creates a setup with 1 standard MySQL server, followed by a 2-node Galera cluster
++#
++
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++log-bin=mysqld-bin
++binlog-format=row
++server-id=1
++
++[mysqld.2]
++binlog-format=row
++server-id=2
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[mysqld.3]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
++wsrep_provider_options='base_port=@mysqld.3.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.3.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++innodb_flush_log_at_trx_commit=2
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_MYPORT_3= @mysqld.2.port
++NODE_MYSOCK_3= @mysqld.2.socket
++
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++NODE_GALERAPORT_3= @mysqld.3.#galera_port
++
++NODE_SSTPORT_2= @mysqld.2.#sst_port
++NODE_SSTPORT_3= @mysqld.3.#sst_port
+diff --git a/mysql-test/suite/galera/galera_4nodes.cnf b/mysql-test/suite/galera/galera_4nodes.cnf
+new file mode 100644
+index 0000000..068c734
+--- /dev/null
++++ b/mysql-test/suite/galera/galera_4nodes.cnf
+@@ -0,0 +1,97 @@
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.1.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.2]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.3]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.3.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.3.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.4]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.4.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.4.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_MYPORT_3= @mysqld.3.port
++NODE_MYSOCK_3= @mysqld.3.socket
++
++NODE_MYPORT_4= @mysqld.4.port
++NODE_MYSOCK_4= @mysqld.4.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++NODE_GALERAPORT_3= @mysqld.3.#galera_port
++NODE_GALERAPORT_4= @mysqld.4.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
++NODE_SSTPORT_3= @mysqld.3.#sst_port
++NODE_SSTPORT_4= @mysqld.4.#sst_port
+diff --git a/mysql-test/suite/galera/include/galera_have_debug_sync.inc b/mysql-test/suite/galera/include/galera_have_debug_sync.inc
+new file mode 100644
+index 0000000..7c01560
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_have_debug_sync.inc
+@@ -0,0 +1,9 @@
++--disable_query_log
++
++--let $galera_have_debug_sync = `SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'`
++
++--if (!$galera_have_debug_sync) {
++      --skip "Test requires Galera debug library with debug_sync functionality"
++}
++
++--enable_query_log
+diff --git a/mysql-test/suite/galera/include/galera_load_provider.inc b/mysql-test/suite/galera/include/galera_load_provider.inc
+new file mode 100644
+index 0000000..0ecf43e
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_load_provider.inc
+@@ -0,0 +1,10 @@
++--echo Loading wsrep provider ...
++
++--disable_query_log
++--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++--enable_reconnect
++--source include/wait_until_connected_again.inc
++--source include/galera_wait_ready.inc
+diff --git a/mysql-test/suite/galera/include/galera_reset_cluster_address.inc b/mysql-test/suite/galera/include/galera_reset_cluster_address.inc
+new file mode 100644
+index 0000000..02937ec
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_reset_cluster_address.inc
+@@ -0,0 +1,12 @@
++--echo Resetting wsrep_cluster_address
++
++--let $wsrep_cluster_size_orig = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'`
++
++SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++
++--source include/wait_until_connected_again.inc
++
++# Wait for wsrep_cluster_size to go back to its original value
++
++--let $wait_condition = SELECT VARIABLE_VALUE = $wsrep_cluster_size_orig FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
+diff --git a/mysql-test/suite/galera/include/galera_sst_restore.inc b/mysql-test/suite/galera/include/galera_sst_restore.inc
+new file mode 100644
+index 0000000..a08b148
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_sst_restore.inc
+@@ -0,0 +1,29 @@
++#
++# Restore the various options used for SST to their original values
++# so that MTR's end-of-test checks are happy.
++#
++
++--connection node_1
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++
++--disable_query_log
++--eval SET GLOBAL wsrep_sst_auth = '$wsrep_sst_auth_orig';
++--enable_query_log
++
++--error 0,ER_CANNOT_USER
++DROP USER sst;
++
++--connection node_2
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
++CALL mtr.add_suppression("InnoDB: New log files created");
++CALL mtr.add_suppression("InnoDB: Creating foreign key constraint system tables");
++CALL mtr.add_suppression("Can't open and lock time zone table");
++CALL mtr.add_suppression("Can't open and lock privilege tables");
++CALL mtr.add_suppression("Info table is not ready to be used");
++CALL mtr.add_suppression("Native table .* has the wrong structure");
++
++--disable_query_log
++--eval SET GLOBAL wsrep_sst_method = '$wsrep_sst_method_orig';
++--eval SET GLOBAL wsrep_sst_receive_address = '$wsrep_sst_receive_address_orig';
++--enable_query_log
+diff --git a/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc b/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc
+new file mode 100644
+index 0000000..405c16c
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc
+@@ -0,0 +1,22 @@
++#
++# Set all the variables required for the SST to be performed via mysqldump
++#
++
++--echo Setting SST method to mysqldump ...
++
++--connection node_1
++# We need a user with a password to perform SST, otherwise we hit LP #1378253
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++
++--let $wsrep_sst_auth_orig = `SELECT @@wsrep_sst_auth`
++SET GLOBAL wsrep_sst_auth = 'sst:sst';
++
++--connection node_2
++--let $wsrep_sst_method_orig = `SELECT @@wsrep_sst_method`
++--let $wsrep_sst_receive_address_orig = `SELECT @@wsrep_sst_receive_address`
++
++--disable_query_log
++# Set wsrep_sst_receive_address to the SQL port
++--eval SET GLOBAL wsrep_sst_receive_address = '127.0.0.2:$NODE_MYPORT_2';
++--enable_query_log
++SET GLOBAL wsrep_sst_method = 'mysqldump';
+diff --git a/mysql-test/suite/galera/include/galera_st_clean_slave.inc b/mysql-test/suite/galera/include/galera_st_clean_slave.inc
+new file mode 100644
+index 0000000..3a49f4f
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_st_clean_slave.inc
+@@ -0,0 +1,115 @@
++--echo Performing State Transfer on a server that starts from a clean var directory
++--echo This is accomplished by shutting down node #2 and removing its var directory before restarting it
++
++--connection node_1
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++
++--echo Shutting down server ...
++--source include/shutdown_mysqld.inc
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++--echo Cleaning var directory ...
++--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mtr
++--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/performance_schema
++--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/test
++--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mysql
++--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++
++--connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++
++--connection node_2
++--echo Starting server ...
++--source include/start_mysqld.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++
++--connection node_1a_galera_st_clean_slave
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_1
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc b/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc
+new file mode 100644
+index 0000000..c886974
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc
+@@ -0,0 +1,105 @@
++--echo Performing State Transfer on a server that has been temporarily disconnected
++
++--connection node_1
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++
++--source suite/galera/include/galera_unload_provider.inc
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++
++--connect node_1a_galera_st_disconnect_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++
++--connection node_2
++--source suite/galera/include/galera_load_provider.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++
++--connection node_1a_galera_st_disconnect_slave
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_1
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/include/galera_st_kill_slave.inc b/mysql-test/suite/galera/include/galera_st_kill_slave.inc
+new file mode 100644
+index 0000000..534d7b6
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_st_kill_slave.inc
+@@ -0,0 +1,110 @@
++--echo Performing State Transfer on a server that has been killed and restarted
++
++--connection node_1
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++
++--source include/kill_galera.inc
++
++--connection node_1
++--source include/wait_until_connected_again.inc
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++
++--connect node_1a_galera_st_kill_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++
++--connection node_2
++--let $galera_wsrep_recover_server_id=2
++--source suite/galera/include/galera_wsrep_recover.inc
++
++--echo Starting server ...
++--source include/start_mysqld.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++
++--connection node_1a_galera_st_kill_slave
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_1
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc b/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc
+new file mode 100644
+index 0000000..8b99b1e
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc
+@@ -0,0 +1,123 @@
++--echo Performing State Transfer on a server that has been killed and restarted
++--echo while a DDL was in progress on it
++
++--connection node_1
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++
++--connection node_2
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++
++# Suspend the applier as it applies the ALTER TABLE
++--let $debug_orig = `SELECT @@debug`
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++
++--connection node_1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++--connection node_2
++SET wsrep_sync_wait = 0;
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: now'
++--source include/wait_condition.inc
++
++--source include/kill_galera.inc
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++
++--connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++
++--connection node_2
++--let $galera_wsrep_recover_server_id=2
++--source suite/galera/include/galera_wsrep_recover.inc
++
++--connection node_2
++--echo Starting server ...
++--source include/start_mysqld.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++
++--connection node_1a_galera_st_kill_slave_ddl
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_1
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/include/galera_st_shutdown_slave.inc b/mysql-test/suite/galera/include/galera_st_shutdown_slave.inc
+new file mode 100644
+index 0000000..6c09b0c
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_st_shutdown_slave.inc
+@@ -0,0 +1,107 @@
++--echo Performing State Transfer on a server that has been shut down cleanly and restarted
++
++--connection node_1
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++
++--echo Shutting down server ...
++--source include/shutdown_mysqld.inc
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++
++--connect node_1a_galera_st_shutdown_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++
++--connection node_2
++--echo Starting server ...
++--source include/start_mysqld.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++
++--connection node_1a_galera_st_shutdown_slave
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_1
++SELECT COUNT(*) = 35 FROM t1;
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/include/galera_unload_provider.inc b/mysql-test/suite/galera/include/galera_unload_provider.inc
+new file mode 100644
+index 0000000..edc7eb3
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_unload_provider.inc
+@@ -0,0 +1,7 @@
++--echo Unloading wsrep provider ...
++
++--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
++--let $wsrep_provider_orig = `SELECT @@wsrep_provider`
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++
++SET GLOBAL wsrep_provider = 'none';
+diff --git a/mysql-test/suite/galera/include/galera_wsrep_recover.inc b/mysql-test/suite/galera/include/galera_wsrep_recover.inc
+new file mode 100644
+index 0000000..3126955
+--- /dev/null
++++ b/mysql-test/suite/galera/include/galera_wsrep_recover.inc
+@@ -0,0 +1,23 @@
++--echo Performing --wsrep-recover ...
++--exec $MYSQLD --defaults-group-suffix=.$galera_wsrep_recover_server_id --defaults-file=$MYSQLTEST_VARDIR/my.cnf --wsrep-recover > $MYSQL_TMP_DIR/galera_wsrep_recover.log 2>&1
++
++--perl
++      use strict;
++        my $wsrep_start_position_str = "grep 'WSREP: Recovered position:' $ENV{MYSQL_TMP_DIR}/galera_wsrep_recover.log | sed 's/.*WSREP\:\ Recovered\ position://' | sed 's/^[ \t]*//'";
++        my $wsrep_start_position = `grep 'WSREP: Recovered position:' $ENV{MYSQL_TMP_DIR}/galera_wsrep_recover.log | sed 's/.*WSREP\:\ Recovered\ position://' | sed 's/^[ \t]*//'`;
++        chomp($wsrep_start_position);
++
++        die if $wsrep_start_position eq '';
++
++      open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/galera_wsrep_start_position.inc") or die;
++        print FILE "--let \$galera_wsrep_start_position = $wsrep_start_position\n";
++        close FILE;
++EOF
++
++--source $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
++
++if ($galera_wsrep_start_position == '') {
++    --die "Could not obtain wsrep_start_position."
++}
++
++--remove_file $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
+diff --git a/mysql-test/suite/galera/my.cnf b/mysql-test/suite/galera/my.cnf
+new file mode 100644
+index 0000000..ca163a5
+--- /dev/null
++++ b/mysql-test/suite/galera/my.cnf
+@@ -0,0 +1 @@
++!include galera_2nodes.cnf
+diff --git a/mysql-test/suite/galera/r/galera_account_management.result b/mysql-test/suite/galera/r/galera_account_management.result
+new file mode 100644
+index 0000000..9b3ae9b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_account_management.result
+@@ -0,0 +1,40 @@
++CREATE USER user1, user2 IDENTIFIED BY 'password';
++SELECT COUNT(*) = 2 FROM mysql.user WHERE user IN ('user1', 'user2');
++COUNT(*) = 2
++1
++RENAME USER user2 TO user3;
++SELECT COUNT(*) = 0 FROM mysql.user WHERE user = 'user2';
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM mysql.user WHERE user = 'user3';
++COUNT(*) = 1
++1
++SET PASSWORD FOR user3 = PASSWORD('foo');
++SELECT password != '' FROM mysql.user WHERE user = 'user3';
++password != ''
++1
++DROP USER user1, user3;
++SELECT COUNT(*) = 0 FROM mysql.user WHERE user IN ('user1', 'user2');
++COUNT(*) = 0
++1
++GRANT ALL ON *.* TO user4 IDENTIFIED BY 'password';
++SELECT COUNT(*) = 1 FROM mysql.user WHERE user = 'user4';
++COUNT(*) = 1
++1
++SELECT Select_priv = 'Y' FROM mysql.user WHERE user = 'user4';
++Select_priv = 'Y'
++1
++CREATE USER user5;
++GRANT PROXY ON user4 TO user5;
++SELECT COUNT(*) = 1 FROM mysql.proxies_priv WHERE user = 'user5';
++COUNT(*) = 1
++1
++REVOKE ALL PRIVILEGES ON *.* FROM user4;
++SELECT Select_priv = 'N' FROM mysql.user WHERE user = 'user4';
++Select_priv = 'N'
++1
++REVOKE PROXY ON user4 FROM user5;
++SELECT COUNT(*) = 0 FROM mysql.proxies_priv WHERE user = 'user5';
++COUNT(*) = 0
++1
++DROP USER user4, user5;
+diff --git a/mysql-test/suite/galera/r/galera_alter_engine_innodb.result b/mysql-test/suite/galera/r/galera_alter_engine_innodb.result
+new file mode 100644
+index 0000000..2b30ac5
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_alter_engine_innodb.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++ALTER TABLE t1 ENGINE=InnoDB;
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++ENGINE = 'InnoDB'
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_alter_engine_myisam.result b/mysql-test/suite/galera/r/galera_alter_engine_myisam.result
+new file mode 100644
+index 0000000..280cb58
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_alter_engine_myisam.result
+@@ -0,0 +1,11 @@
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++INSERT INTO t1 VALUES (1);
++ALTER TABLE t1 ENGINE=InnoDB;
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++ENGINE = 'InnoDB'
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_alter_table_force.result b/mysql-test/suite/galera/r/galera_alter_table_force.result
+new file mode 100644
+index 0000000..401ab46
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_alter_table_force.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++ALTER TABLE t1 FORCE;
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++ENGINE = 'InnoDB'
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_as_master.result b/mysql-test/suite/galera/r/galera_as_master.result
+new file mode 100644
+index 0000000..cca5535
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_as_master.result
+@@ -0,0 +1,9 @@
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++INSERT INTO t1 VALUES(2);
++DROP TABLE t1;
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/r/galera_as_master_gtid.result b/mysql-test/suite/galera/r/galera_as_master_gtid.result
+new file mode 100644
+index 0000000..8dfe462
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_as_master_gtid.result
+@@ -0,0 +1,59 @@
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++uuids_do_not_match
++1
++SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 120;
++Log_name      Pos     Event_type      Server_id       End_log_pos     Info
++mysqld-bin.000002     120     Previous_gtids  1       151     
++mysqld-bin.000002     151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
++mysqld-bin.000002     199     Query   1       327     use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
++mysqld-bin.000002     327     Gtid    1       375     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
++mysqld-bin.000002     375     Query   1       452     BEGIN
++mysqld-bin.000002     452     Table_map       1       497     table_id: # (test.t1)
++mysqld-bin.000002     497     Write_rows      1       537     table_id: # flags: STMT_END_F
++mysqld-bin.000002     537     Xid     1       568     COMMIT /* xid=# */
++INSERT INTO t1 VALUES(2);
++uuids_do_not_match
++1
++uuids_match
++1
++SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 120;
++Log_name      Pos     Event_type      Server_id       End_log_pos     Info
++mysqld-bin.000003     120     Previous_gtids  2       151     
++mysqld-bin.000003     151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
++mysqld-bin.000003     199     Query   1       327     use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
++mysqld-bin.000003     327     Gtid    1       375     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
++mysqld-bin.000003     375     Query   1       443     BEGIN
++mysqld-bin.000003     443     Table_map       1       488     table_id: # (test.t1)
++mysqld-bin.000003     488     Write_rows      1       528     table_id: # flags: STMT_END_F
++mysqld-bin.000003     528     Xid     1       559     COMMIT /* xid=# */
++mysqld-bin.000003     559     Gtid    2       607     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
++mysqld-bin.000003     607     Query   2       684     BEGIN
++mysqld-bin.000003     684     Table_map       2       729     table_id: # (test.t1)
++mysqld-bin.000003     729     Write_rows      2       769     table_id: # flags: STMT_END_F
++mysqld-bin.000003     769     Xid     2       800     COMMIT /* xid=# */
++uuids_do_not_match
++1
++uuids_match
++1
++SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
++Log_name      Pos     Event_type      Server_id       End_log_pos     Info
++mysqld-bin.000001     120     Previous_gtids  3       151     
++mysqld-bin.000001     151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
++mysqld-bin.000001     199     Query   1       327     use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
++mysqld-bin.000001     327     Gtid    1       375     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
++mysqld-bin.000001     375     Query   1       443     BEGIN
++mysqld-bin.000001     443     Table_map       1       488     table_id: # (test.t1)
++mysqld-bin.000001     488     Write_rows      1       528     table_id: # flags: STMT_END_F
++mysqld-bin.000001     528     Xid     1       559     COMMIT /* xid=# */
++mysqld-bin.000001     559     Gtid    2       607     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
++mysqld-bin.000001     607     Query   2       675     BEGIN
++mysqld-bin.000001     675     Table_map       2       720     table_id: # (test.t1)
++mysqld-bin.000001     720     Write_rows      2       760     table_id: # flags: STMT_END_F
++mysqld-bin.000001     760     Xid     2       791     COMMIT /* xid=# */
++DROP TABLE t1;
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/r/galera_as_master_gtid_change_master.result b/mysql-test/suite/galera/r/galera_as_master_gtid_change_master.result
+new file mode 100644
+index 0000000..80fbccf
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_as_master_gtid_change_master.result
+@@ -0,0 +1,15 @@
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++INSERT INTO t1 VALUES(2);
++STOP SLAVE;
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++INSERT INTO t1 VALUES(3);
++INSERT INTO t1 VALUES(4);
++DROP TABLE t1;
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/r/galera_as_slave.result b/mysql-test/suite/galera/r/galera_as_slave.result
+new file mode 100644
+index 0000000..f03c813
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_as_slave.result
+@@ -0,0 +1,16 @@
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++INSERT INTO t1 VALUES (3);
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++DROP TABLE t1;
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/r/galera_as_slave_gtid.result b/mysql-test/suite/galera/r/galera_as_slave_gtid.result
+new file mode 100644
+index 0000000..f7ee666
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_as_slave_gtid.result
+@@ -0,0 +1,18 @@
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++SELECT LENGTH(@@global.gtid_executed) > 1;
++LENGTH(@@global.gtid_executed) > 1
++1
++gtid_executed_equal
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++gtid_executed_equal
++1
++DROP TABLE t1;
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort.result b/mysql-test/suite/galera/r/galera_bf_abort.result
+new file mode 100644
+index 0000000..c55f1a4
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (2);
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort_for_update.result b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result
+new file mode 100644
+index 0000000..3978a3d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (1);
++SELECT * FROM t1 FOR UPDATE;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result b/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result
+new file mode 100644
+index 0000000..e381917
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result
+@@ -0,0 +1,8 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++FLUSH TABLES WITH READ LOCK;;
++INSERT INTO t1 VALUES (1);
++UNLOCK TABLES;
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result
+new file mode 100644
+index 0000000..2e44a77
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SELECT GET_LOCK("foo", 1000);
++GET_LOCK("foo", 1000)
++1
++SET AUTOCOMMIT=OFF;
++INSERT INTO t1 VALUES (1);
++SELECT GET_LOCK("foo", 1000);;
++INSERT INTO t1 VALUES (1);
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result b/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
+new file mode 100644
+index 0000000..e657e72
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
+@@ -0,0 +1,8 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++LOCK TABLE t1 WRITE;
++INSERT INTO t1 VALUES (1);;
++INSERT INTO t1 VALUES (2);
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_bf_abort_sleep.result b/mysql-test/suite/galera/r/galera_bf_abort_sleep.result
+new file mode 100644
+index 0000000..8e85a5f
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_bf_abort_sleep.result
+@@ -0,0 +1,9 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++INSERT INTO t1 VALUES (1);
++SELECT SLEEP(1000);;
++INSERT INTO t1 VALUES (1);
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++wsrep_local_aborts_increment
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_cache_size.result b/mysql-test/suite/galera/r/galera_binlog_cache_size.result
+new file mode 100644
+index 0000000..9726cf2
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_cache_size.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 VARCHAR(767)) ENGINE=InnoDB;
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++SET GLOBAL binlog_cache_size=4096;
++SET GLOBAL max_binlog_cache_size=4096;
++SET AUTOCOMMIT=ON;
++START TRANSACTION;
++INSERT INTO t1 SELECT REPEAT('a', 767) FROM ten;
++INSERT INTO t1 SELECT REPEAT('a', 767) FROM ten;
++ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_checksum.result b/mysql-test/suite/galera/r/galera_binlog_checksum.result
+new file mode 100644
+index 0000000..a6ab623
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_checksum.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result b/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result
+new file mode 100644
+index 0000000..4156c0c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result
+@@ -0,0 +1,9 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 VARCHAR(1000));
++INSERT INTO t1 SELECT REPEAT('x', 1000) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++SELECT COUNT(*) = 10000 FROM t1;
++COUNT(*) = 10000
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result b/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result
+new file mode 100644
+index 0000000..984a943
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result
+@@ -0,0 +1,6 @@
++CREATE TABLE t1 (f1 VARCHAR(1000));
++INSERT INTO t1 VALUES (REPEAT('x', 1000));
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = REPEAT('x', 1000);
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_row_image.result b/mysql-test/suite/galera/r/galera_binlog_row_image.result
+new file mode 100644
+index 0000000..a1f0fb4
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_row_image.result
+@@ -0,0 +1,79 @@
++SET SESSION binlog_row_image=minimal;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER NOT NULL UNIQUE) ENGINE=InnoDB;
++CREATE TABLE t3 (f1 VARCHAR(1)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t3 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t3 WHERE f1 = 1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++UPDATE t2 SET f1 = 2 WHERE f1 = 1;
++UPDATE t3 SET f1 = 2 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 2;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t3 WHERE f1 = 2;
++COUNT(*) = 1
++1
++DELETE FROM t1;
++DELETE FROM t2;
++DELETE FROM t3;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t3;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++SET SESSION binlog_row_image=noblob;
++CREATE TABLE t1 (f1 BLOB, f2 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t1 VALUES ('abc', 1);
++INSERT INTO t2 VALUES ('abc');
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'abc';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 'abc';
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 'xyz';
++UPDATE t2 SET f1 = 'xyz';
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'xyz';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 'xyz';
++COUNT(*) = 1
++1
++UPDATE t1 SET f2 = 2 WHERE f2 = 1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 2;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'xyz';
++COUNT(*) = 1
++1
++DELETE FROM t1;
++DELETE FROM t2;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_binlog_rows_query_log_events.result b/mysql-test/suite/galera/r/galera_binlog_rows_query_log_events.result
+new file mode 100644
+index 0000000..80ae3d0
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_binlog_rows_query_log_events.result
+@@ -0,0 +1,12 @@
++SET GLOBAL binlog_rows_query_log_events=TRUE;
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++COUNT(*) = 1
++1
++SET GLOBAL binlog_rows_query_log_events = 0;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_create_function.result b/mysql-test/suite/galera/r/galera_create_function.result
+new file mode 100644
+index 0000000..4d19faf
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_create_function.result
+@@ -0,0 +1,55 @@
++CREATE USER 'user1';
++CREATE
++DEFINER = 'user1'
++FUNCTION f1 (param INTEGER)
++RETURNS VARCHAR(200)
++COMMENT 'f1_comment'
++LANGUAGE SQL
++NOT DETERMINISTIC
++MODIFIES SQL DATA
++SQL SECURITY DEFINER
++RETURN 'abc';
++GRANT EXECUTE ON FUNCTION f1 TO user1;
++CREATE
++DEFINER = CURRENT_USER
++FUNCTION f2 (param VARCHAR(100))
++RETURNS INTEGER
++DETERMINISTIC
++NO SQL
++SQL SECURITY INVOKER
++RETURN 123;
++SHOW CREATE FUNCTION f1;
++Function      sql_mode        Create Function character_set_client    collation_connection    Database Collation
++f1    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`user1`@`%` FUNCTION `f1`(param INTEGER) RETURNS varchar(200) CHARSET latin1
++    MODIFIES SQL DATA
++    COMMENT 'f1_comment'
++RETURN 'abc'  latin1  latin1_swedish_ci       latin1_swedish_ci
++SHOW CREATE FUNCTION f1;
++Function      sql_mode        Create Function character_set_client    collation_connection    Database Collation
++f1    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`user1`@`%` FUNCTION `f1`(param INTEGER) RETURNS varchar(200) CHARSET latin1
++    MODIFIES SQL DATA
++    COMMENT 'f1_comment'
++RETURN 'abc'  latin1  latin1_swedish_ci       latin1_swedish_ci
++SHOW CREATE FUNCTION f2;
++Function      sql_mode        Create Function character_set_client    collation_connection    Database Collation
++f2    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`root`@`localhost` FUNCTION `f2`(param VARCHAR(100)) RETURNS int(11)
++    NO SQL
++    DETERMINISTIC
++    SQL SECURITY INVOKER
++RETURN 123    latin1  latin1_swedish_ci       latin1_swedish_ci
++SHOW CREATE FUNCTION f2;
++Function      sql_mode        Create Function character_set_client    collation_connection    Database Collation
++f2    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`root`@`localhost` FUNCTION `f2`(param VARCHAR(100)) RETURNS int(11)
++    NO SQL
++    DETERMINISTIC
++    SQL SECURITY INVOKER
++RETURN 123    latin1  latin1_swedish_ci       latin1_swedish_ci
++SELECT f1(1) = 'abc';
++f1(1) = 'abc'
++1
++SELECT f2('abc') = 123;
++f2('abc') = 123
++1
++DROP FUNCTION f1;
++DROP FUNCTION f2;
++DROP USER 'user1';
+diff --git a/mysql-test/suite/galera/r/galera_create_procedure.result b/mysql-test/suite/galera/r/galera_create_procedure.result
+new file mode 100644
+index 0000000..997bbba
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_create_procedure.result
+@@ -0,0 +1,53 @@
++CREATE USER 'user1';
++CREATE TABLE t1 (f1 INTEGER);
++CREATE
++DEFINER = 'user1'
++PROCEDURE p1 (IN param1 INTEGER, OUT param2 INTEGER, INOUT param3 INTEGER)
++COMMENT 'p1_comment'
++LANGUAGE SQL
++NOT DETERMINISTIC
++MODIFIES SQL DATA
++SQL SECURITY DEFINER
++INSERT INTO t1 VALUES (1);
++GRANT EXECUTE ON PROCEDURE p1 TO user1;
++CREATE
++DEFINER = CURRENT_USER
++PROCEDURE p2 (param VARCHAR(100))
++DETERMINISTIC
++NO SQL
++SQL SECURITY INVOKER BEGIN END ;
++SHOW CREATE PROCEDURE p1;
++Procedure     sql_mode        Create Procedure        character_set_client    collation_connection    Database Collation
++p1    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`user1`@`%` PROCEDURE `p1`(IN param1 INTEGER, OUT param2 INTEGER, INOUT param3 INTEGER)
++    MODIFIES SQL DATA
++    COMMENT 'p1_comment'
++INSERT INTO t1 VALUES (1)     latin1  latin1_swedish_ci       latin1_swedish_ci
++SELECT 1 FROM DUAL;
++1
++1
++SHOW CREATE PROCEDURE p1;
++Procedure     sql_mode        Create Procedure        character_set_client    collation_connection    Database Collation
++p1    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`user1`@`%` PROCEDURE `p1`(IN param1 INTEGER, OUT param2 INTEGER, INOUT param3 INTEGER)
++    MODIFIES SQL DATA
++    COMMENT 'p1_comment'
++INSERT INTO t1 VALUES (1)     latin1  latin1_swedish_ci       latin1_swedish_ci
++SHOW CREATE PROCEDURE p2;
++Procedure     sql_mode        Create Procedure        character_set_client    collation_connection    Database Collation
++p2    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`root`@`localhost` PROCEDURE `p2`(param VARCHAR(100))
++    NO SQL
++    DETERMINISTIC
++    SQL SECURITY INVOKER
++BEGIN END     latin1  latin1_swedish_ci       latin1_swedish_ci
++SHOW CREATE PROCEDURE p2;
++Procedure     sql_mode        Create Procedure        character_set_client    collation_connection    Database Collation
++p2    NO_ENGINE_SUBSTITUTION  CREATE DEFINER=`root`@`localhost` PROCEDURE `p2`(param VARCHAR(100))
++    NO SQL
++    DETERMINISTIC
++    SQL SECURITY INVOKER
++BEGIN END     latin1  latin1_swedish_ci       latin1_swedish_ci
++CALL p1(@a, @b, @c);
++CALL p2('abc');
++DROP PROCEDURE p1;
++DROP PROCEDURE p2;
++DROP USER 'user1';
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_create_table_like.result b/mysql-test/suite/galera/r/galera_create_table_like.result
+new file mode 100644
+index 0000000..b335101
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_create_table_like.result
+@@ -0,0 +1,47 @@
++CREATE SCHEMA schema1;
++CREATE SCHEMA schema2;
++USE schema1;
++CREATE TABLE real_table (f1 INTEGER) ENGINE=InnoDB;
++CREATE TEMPORARY TABLE temp_table (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE myisam_table (f1 INTEGER) ENGINE=MyISAM;
++USE schema2;
++CREATE TABLE real_table1 LIKE schema1.real_table;
++CREATE TABLE real_table2 LIKE schema1.temp_table;
++CREATE TABLE real_table3 LIKE schema1.myisam_table;
++CREATE TEMPORARY TABLE temp_table1 LIKE schema1.real_table;
++CREATE TEMPORARY TABLE temp_table2 LIKE schema1.temp_table;
++CREATE TEMPORARY TABLE temp_table3 LIKE schema1.myisam_table;
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table' AND TABLE_SCHEMA = 'schema1';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'myisam_table' AND TABLE_SCHEMA = 'schema1';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table' AND TABLE_SCHEMA = 'schema1';
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table1' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table2' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table3' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table1' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table2' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table3' AND TABLE_SCHEMA = 'schema2';
++COUNT(*) = 0
++1
++DROP TABLE schema1.real_table;
++DROP TABLE schema1.myisam_table;
++DROP TABLE schema2.real_table1;
++DROP TABLE schema2.real_table2;
++DROP TABLE schema2.real_table3;
++DROP SCHEMA schema1;
++DROP SCHEMA schema2;
+diff --git a/mysql-test/suite/galera/r/galera_create_trigger.result b/mysql-test/suite/galera/r/galera_create_trigger.result
+new file mode 100644
+index 0000000..7e65608
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_create_trigger.result
+@@ -0,0 +1,42 @@
++CREATE TABLE definer_root (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_current_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_default (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE USER 'user1';
++CREATE DEFINER=root@localhost TRIGGER definer_root BEFORE INSERT ON definer_root FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE DEFINER=user1 TRIGGER definer_user BEFORE INSERT ON definer_user FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE DEFINER=current_user TRIGGER definer_current_user BEFORE INSERT ON definer_current_user FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE TRIGGER definer_default BEFORE INSERT ON definer_default FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++INSERT INTO definer_root (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_root';
++DEFINER = 'root@localhost'
++1
++SELECT trigger_user = 'root@localhost' FROM definer_root;
++trigger_user = 'root@localhost'
++1
++INSERT INTO definer_user (f1) VALUES (1);
++SELECT DEFINER = 'user1@%' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_user';
++DEFINER = 'user1@%'
++1
++SELECT trigger_user = 'user1@%' FROM definer_user;
++trigger_user = 'user1@%'
++1
++INSERT INTO definer_current_user (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_current_user';
++DEFINER = 'root@localhost'
++1
++SELECT trigger_user = 'root@localhost' FROM definer_current_user;
++trigger_user = 'root@localhost'
++1
++INSERT INTO definer_default (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_default';
++DEFINER = 'root@localhost'
++1
++SELECT trigger_user = 'root@localhost' FROM definer_default;
++trigger_user = 'root@localhost'
++1
++DROP TABLE definer_current_user;
++DROP TABLE definer_user;
++DROP TABLE definer_root;
++DROP TABLE definer_default;
++DROP USER 'user1';
+diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result
+new file mode 100644
+index 0000000..8bd2221
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_defaults.result
+@@ -0,0 +1,117 @@
++SELECT COUNT(*) = 40 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
++COUNT(*) = 40
++1
++SELECT VARIABLE_NAME, VARIABLE_VALUE
++FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME NOT IN (
++'WSREP_PROVIDER_OPTIONS',
++'WSREP_SST_RECEIVE_ADDRESS',
++'WSREP_NODE_ADDRESS',
++'WSREP_NODE_NAME',
++'WSREP_PROVIDER',
++'WSREP_DATA_HOME_DIR',
++'WSREP_NODE_INCOMING_ADDRESS',
++'WSREP_START_POSITION'
++)
++ORDER BY VARIABLE_NAME;
++VARIABLE_NAME VARIABLE_VALUE
++WSREP_AUTO_INCREMENT_CONTROL  ON
++WSREP_CAUSAL_READS    ON
++WSREP_CERTIFY_NONPK   ON
++WSREP_CLUSTER_ADDRESS gcomm://
++WSREP_CLUSTER_NAME    my_wsrep_cluster
++WSREP_CONVERT_LOCK_TO_TRX     OFF
++WSREP_DBUG_OPTION     
++WSREP_DEBUG   OFF
++WSREP_DESYNC  OFF
++WSREP_DRUPAL_282555_WORKAROUND        OFF
++WSREP_FORCED_BINLOG_FORMAT    NONE
++WSREP_LOAD_DATA_SPLITTING     ON
++WSREP_LOG_CONFLICTS   OFF
++WSREP_MAX_WS_ROWS     131072
++WSREP_MAX_WS_SIZE     1073741824
++WSREP_MYSQL_REPLICATION_BUNDLE        0
++WSREP_NOTIFY_CMD      
++WSREP_ON      ON
++WSREP_OSU_METHOD      TOI
++WSREP_PREORDERED      OFF
++WSREP_RECOVER OFF
++WSREP_REPLICATE_MYISAM        OFF
++WSREP_RESTART_SLAVE   OFF
++WSREP_RETRY_AUTOCOMMIT        1
++WSREP_SLAVE_FK_CHECKS ON
++WSREP_SLAVE_THREADS   1
++WSREP_SLAVE_UK_CHECKS OFF
++WSREP_SST_AUTH        
++WSREP_SST_DONOR       
++WSREP_SST_DONOR_REJECTS_QUERIES       OFF
++WSREP_SST_METHOD      rsync
++WSREP_SYNC_WAIT       7
++<BASE_DIR>; <BASE_HOST>; <BASE_PORT>; cert.log_conflicts = no; debug = no; evs.auto_evict = 0; evs.causal_keepalive_period = PT1S; evs.debug_log_mask = 0x1; evs.delay_margin = PT1S; evs.delayed_keep_period = PT30S; evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S; evs.info_log_mask = 0; evs.install_timeout = PT7.5S; evs.join_retrans_period = PT1S; evs.keepalive_period = PT1S; evs.max_install_timeouts = 3; evs.send_window = 4; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S; evs.use_aggregate = true; evs.user_send_window = 2; evs.version = 0; evs.view_forget_timeout = P1D; <GCACHE_DIR>; gcache.keep_pages_size = 0; gcache.mem_size = 0; <GCACHE_NAME>; gcache.page_size = 128M; gcache.size = 128M; gcs.fc_debug = 0; gcs.fc_factor = 1.0; gcs.fc_limit = 16; gcs.fc_master_slave = no; gcs.max_packet_size = 64500; gcs.max_throttle = 0.25; gcs.recv_q_hard_limit = 9223372036854775807; gcs.recv_q_soft_limit = 0.25; gcs.sync_donor = no; <GMCAST_LISTEN_ADDR>; gmcast.mcast_addr = ; gmcast.mcast_ttl = 1; gmcast.peer_timeout = PT3S; gmcast.segment = 0; gmcast.time_wait = PT5S; gmcast.version = 0; <IST_RECV_ADDR>; pc.announce_timeout = PT3S; pc.checksum = false; pc.ignore_quorum = false; pc.ignore_sb = false; pc.linger = PT20S; pc.npvo = false; pc.recovery = true; pc.version = 0; pc.wait_prim = true; pc.wait_prim_timeout = P30S; pc.weight = 1; protonet.backend = asio; protonet.version = 0; repl.causal_read_timeout = PT30S; repl.commit_order = 3; repl.key_format = FLAT8; repl.max_ws_size = 2147483647; repl.proto_max = 7; socket.checksum = 2; 
++SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_STATUS
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME != 'wsrep_debug_sync_waiters';
++COUNT(*)
++56
++SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_STATUS
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME != 'wsrep_debug_sync_waiters'
++ORDER BY VARIABLE_NAME;
++VARIABLE_NAME
++WSREP_APPLY_OOOE
++WSREP_APPLY_OOOL
++WSREP_APPLY_WINDOW
++WSREP_CAUSAL_READS
++WSREP_CERT_DEPS_DISTANCE
++WSREP_CERT_INDEX_SIZE
++WSREP_CERT_INTERVAL
++WSREP_CLUSTER_CONF_ID
++WSREP_CLUSTER_SIZE
++WSREP_CLUSTER_STATE_UUID
++WSREP_CLUSTER_STATUS
++WSREP_COMMIT_OOOE
++WSREP_COMMIT_OOOL
++WSREP_COMMIT_WINDOW
++WSREP_CONNECTED
++WSREP_EVS_DELAYED
++WSREP_EVS_EVICT_LIST
++WSREP_EVS_REPL_LATENCY
++WSREP_EVS_STATE
++WSREP_FLOW_CONTROL_PAUSED
++WSREP_FLOW_CONTROL_PAUSED_NS
++WSREP_FLOW_CONTROL_RECV
++WSREP_FLOW_CONTROL_SENT
++WSREP_GCOMM_UUID
++WSREP_INCOMING_ADDRESSES
++WSREP_LAST_COMMITTED
++WSREP_LOCAL_BF_ABORTS
++WSREP_LOCAL_CACHED_DOWNTO
++WSREP_LOCAL_CERT_FAILURES
++WSREP_LOCAL_COMMITS
++WSREP_LOCAL_INDEX
++WSREP_LOCAL_RECV_QUEUE
++WSREP_LOCAL_RECV_QUEUE_AVG
++WSREP_LOCAL_RECV_QUEUE_MAX
++WSREP_LOCAL_RECV_QUEUE_MIN
++WSREP_LOCAL_REPLAYS
++WSREP_LOCAL_SEND_QUEUE
++WSREP_LOCAL_SEND_QUEUE_AVG
++WSREP_LOCAL_SEND_QUEUE_MAX
++WSREP_LOCAL_SEND_QUEUE_MIN
++WSREP_LOCAL_STATE
++WSREP_LOCAL_STATE_COMMENT
++WSREP_LOCAL_STATE_UUID
++WSREP_PROTOCOL_VERSION
++WSREP_PROVIDER_NAME
++WSREP_PROVIDER_VENDOR
++WSREP_PROVIDER_VERSION
++WSREP_READY
++WSREP_RECEIVED
++WSREP_RECEIVED_BYTES
++WSREP_REPLICATED
++WSREP_REPLICATED_BYTES
++WSREP_REPL_DATA_BYTES
++WSREP_REPL_KEYS
++WSREP_REPL_KEYS_BYTES
++WSREP_REPL_OTHER_BYTES
+diff --git a/mysql-test/suite/galera/r/galera_delete_limit.result b/mysql-test/suite/galera/r/galera_delete_limit.result
+new file mode 100644
+index 0000000..72bee18
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_delete_limit.result
+@@ -0,0 +1,19 @@
++CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 SELECT f1 FROM ten ORDER BY RAND();
++DELETE FROM t1 ORDER BY RAND() LIMIT 5;
++sum_matches
++1
++max_matches
++1
++DROP TABLE t1;
++CREATE TABLE t2 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t2 SELECT f1 FROM ten ORDER BY RAND();
++DELETE FROM t2 ORDER BY RAND() LIMIT 5;
++sum_matches
++1
++max_matches
++1
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_enum.result b/mysql-test/suite/galera/r/galera_enum.result
+new file mode 100644
+index 0000000..e853c5c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_enum.result
+@@ -0,0 +1,37 @@
++CREATE TABLE t1 (f1 ENUM('', 'one', 'two'), KEY (f1)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES ('');
++INSERT INTO t1 VALUES ('one'), ('two');
++INSERT INTO t1 VALUES (0), (1), (2);
++Warnings:
++Warning       1265    Data truncated for column 'f1' at row 1
++SELECT COUNT(*) = 6 FROM t1;
++COUNT(*) = 6
++1
++SELECT COUNT(*) = 2 FROM t1 where f1 = '';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1 where f1 = 'one';
++COUNT(*) = 2
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 ENUM('', 'one', 'two', 'three', 'four') PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (''), ('one'), ('two');
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = '';
++COUNT(*) = 1
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'three' where f1 = '';
++SET AUTOCOMMIt=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'four' where f1 = '';
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'three';
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_events.result b/mysql-test/suite/galera/r/galera_events.result
+new file mode 100644
+index 0000000..09d8406
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_events.result
+@@ -0,0 +1,18 @@
++CREATE EVENT event1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO SELECT 1;
++SELECT DEFINER= 'root@localhost', ORIGINATOR = 1, STATUS = 'SLAVESIDE_DISABLED', EVENT_TYPE = 'ONE TIME', ON_COMPLETION = 'NOT PRESERVE' FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++DEFINER= 'root@localhost'     ORIGINATOR = 1  STATUS = 'SLAVESIDE_DISABLED'   EVENT_TYPE = 'ONE TIME' ON_COMPLETION = 'NOT PRESERVE'
++1     1       1       1       1
++ALTER EVENT event1 DISABLE;
++SELECT DEFINER= 'root@localhost', ORIGINATOR = 1, STATUS = 'SLAVESIDE_DISABLED', EVENT_TYPE = 'ONE TIME', ON_COMPLETION = 'NOT PRESERVE' FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++DEFINER= 'root@localhost'     ORIGINATOR = 1  STATUS = 'SLAVESIDE_DISABLED'   EVENT_TYPE = 'ONE TIME' ON_COMPLETION = 'NOT PRESERVE'
++1     1       1       1       1
++SET GLOBAL event_scheduler = ON;
++CREATE EVENT event2 ON SCHEDULE AT CURRENT_TIMESTAMP ON COMPLETION NOT PRESERVE DO SELECT 1;
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event2';
++COUNT(*) = 0
++1
++DROP EVENT event1;
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++COUNT(*) = 0
++1
++SET GLOBAL event_scheduler = OFF;;
+diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_delete.result b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result
+new file mode 100644
+index 0000000..89f4301
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result
+@@ -0,0 +1,30 @@
++CREATE TABLE grandparent (
++id INT NOT NULL PRIMARY KEY
++) ENGINE=InnoDB;
++CREATE TABLE parent (
++id INT NOT NULL PRIMARY KEY,
++grandparent_id INT,
++FOREIGN KEY (grandparent_id)
++REFERENCES grandparent(id)
++ON DELETE CASCADE
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT NOT NULL PRIMARY KEY, 
++parent_id INT,
++FOREIGN KEY (parent_id) 
++REFERENCES parent(id)
++ON DELETE CASCADE
++) ENGINE=InnoDB;
++INSERT INTO grandparent VALUES (1),(2);
++INSERT INTO parent VALUES (1,1), (2,2);
++INSERT INTO child VALUES (1,1), (2,2);
++DELETE FROM grandparent WHERE id = 1;
++SELECT COUNT(*) = 0 FROM parent WHERE grandparent_id = 1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1;
++COUNT(*) = 0
++1
++DROP TABLE child;
++DROP TABLE parent;
++DROP TABLE grandparent;
+diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_update.result b/mysql-test/suite/galera/r/galera_fk_cascade_update.result
+new file mode 100644
+index 0000000..2ab2ad3
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_cascade_update.result
+@@ -0,0 +1,30 @@
++CREATE TABLE grandparent (
++id INT NOT NULL PRIMARY KEY
++) ENGINE=InnoDB;
++CREATE TABLE parent (
++id INT NOT NULL PRIMARY KEY,
++grandparent_id INT,
++FOREIGN KEY (grandparent_id)
++REFERENCES grandparent(id)
++ON UPDATE CASCADE
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT NOT NULL PRIMARY KEY, 
++grandparent_id INT,
++FOREIGN KEY (grandparent_id)
++REFERENCES parent(grandparent_id)
++ON UPDATE CASCADE
++) ENGINE=InnoDB;
++INSERT INTO grandparent VALUES (1),(2);
++INSERT INTO parent VALUES (1,1), (2,2);
++INSERT INTO child VALUES (1,1), (2,2);
++UPDATE grandparent SET id = 3 WHERE id = 1;
++SELECT COUNT(*) = 1 FROM parent WHERE grandparent_id = 3;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM child WHERE grandparent_id = 3;
++COUNT(*) = 1
++1
++DROP TABLE child;
++DROP TABLE parent;
++DROP TABLE grandparent;
+diff --git a/mysql-test/suite/galera/r/galera_fk_conflict.result b/mysql-test/suite/galera/r/galera_fk_conflict.result
+new file mode 100644
+index 0000000..ae6c482
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_conflict.result
+@@ -0,0 +1,23 @@
++CREATE TABLE parent (
++id INT PRIMARY KEY,
++KEY (id)
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT PRIMARY KEY,
++parent_id INT,
++FOREIGN KEY (parent_id) 
++REFERENCES parent(id)
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (1), (2);
++INSERT INTO child VALUES (1,1);
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++DELETE FROM parent WHERE id = 2;
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO child VALUES (2, 2);
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/r/galera_fk_mismatch.result b/mysql-test/suite/galera/r/galera_fk_mismatch.result
+new file mode 100644
+index 0000000..07cdb1b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_mismatch.result
+@@ -0,0 +1,25 @@
++CREATE TABLE parent (
++id1 INT,
++id2 INT,
++PRIMARY KEY (id1, id2) /* Multipart PK */
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT PRIMARY KEY,
++parent_id1 INT,
++FOREIGN KEY (parent_id1) 
++REFERENCES parent(id1) /* FK is subset of PK above */
++ON UPDATE CASCADE
++ON DELETE CASCADE
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (1, 2);
++INSERT INTO child VALUES (1, 1);
++UPDATE parent SET id1 = 3 WHERE id1 = 1;
++SELECT COUNT(*) = 1 FROM child WHERE parent_id1 = 3;
++COUNT(*) = 1
++1
++DELETE FROM parent WHERE id1 = 3;
++SELECT COUNT(*) = 0 FROM child WHERE parent_id1 = 3;
++COUNT(*) = 0
++1
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/r/galera_fk_multicolumn.result b/mysql-test/suite/galera/r/galera_fk_multicolumn.result
+new file mode 100644
+index 0000000..a86b87a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_multicolumn.result
+@@ -0,0 +1,35 @@
++CREATE TABLE t0 (
++f1 INT PRIMARY KEY,
++f2 INT UNIQUE
++);
++CREATE TABLE t1 (
++f1 INT PRIMARY KEY,
++FOREIGN KEY (f1)
++REFERENCES t0(f1)
++ON UPDATE CASCADE
++);
++CREATE TABLE t2 (
++f2 INT PRIMARY KEY,
++FOREIGN KEY (f2)
++REFERENCES t0(f2)
++ON UPDATE CASCADE
++);
++INSERT INTO t0 VALUES (0, 0);
++INSERT INTO t1 VALUES (0);
++INSERT INTO t2 VALUES (0);
++UPDATE t0 SET f1 = 1, f2 = 2;
++SELECT f1 = 1 FROM t1 WHERE f1 = 1;
++f1 = 1
++1
++SELECT f2 = 2 FROM t2 WHERE f2 = 2;
++f2 = 2
++1
++SELECT f1 = 1 FROM t1;
++f1 = 1
++1
++SELECT f2 = 2 FROM t2;
++f2 = 2
++1
++DROP TABLE t2;
++DROP TABLE t1;
++DROP TABLE t0;
+diff --git a/mysql-test/suite/galera/r/galera_fk_multitable.result b/mysql-test/suite/galera/r/galera_fk_multitable.result
+new file mode 100644
+index 0000000..e77128d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_multitable.result
+@@ -0,0 +1,22 @@
++CREATE TABLE t0 (
++f0 INT PRIMARY KEY
++);
++CREATE TABLE t1 (
++f1 INT PRIMARY KEY,
++f0 INTEGER,
++FOREIGN KEY (f0)
++REFERENCES t0(f0)
++ON DELETE CASCADE
++);
++INSERT INTO t0 VALUES (0), (1);
++INSERT INTO t1 VALUES (0, 0);
++INSERT INTO t1 VALUES (1, 0);
++DELETE t0.*, t1.* FROM t0, t1 WHERE t0.f0 = 0 AND t1.f1 = 0;
++SELECT COUNT(*) = 1 FROM t0;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++DROP TABLE t0;
+diff --git a/mysql-test/suite/galera/r/galera_fk_no_pk.result b/mysql-test/suite/galera/r/galera_fk_no_pk.result
+new file mode 100644
+index 0000000..e4f9286
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_no_pk.result
+@@ -0,0 +1,28 @@
++CREATE TABLE parent (
++id INT,
++KEY (id)
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT,
++parent_id INT,
++FOREIGN KEY (parent_id) 
++REFERENCES parent(id)
++ON UPDATE CASCADE
++ON DELETE CASCADE
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (1), (1), (2), (2);
++INSERT INTO child VALUES (1,1), (2,2), (1,1), (2,2);
++DELETE FROM parent WHERE id = 1;
++SELECT COUNT(*) = 0 FROM child WHERE id = 1;
++COUNT(*) = 0
++1
++UPDATE parent SET id = 3 WHERE id = 2;
++SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1;
++COUNT(*) = 0
++1
++SELECT parent_id = 3 FROM child WHERE id = 2;
++parent_id = 3
++1
++1
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/r/galera_fk_selfreferential.result b/mysql-test/suite/galera/r/galera_fk_selfreferential.result
+new file mode 100644
+index 0000000..25c3704
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_selfreferential.result
+@@ -0,0 +1,13 @@
++CREATE TABLE t1 (
++f1 INT NOT NULL PRIMARY KEY,
++f2 INT,
++FOREIGN KEY (f2)
++REFERENCES t1(f1)
++ON DELETE CASCADE
++) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1, 1), (2, 1);
++DELETE FROM t1 WHERE f1 = 1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_fk_setnull.result b/mysql-test/suite/galera/r/galera_fk_setnull.result
+new file mode 100644
+index 0000000..f7fb9d0
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fk_setnull.result
+@@ -0,0 +1,30 @@
++CREATE TABLE parent (
++id INT NOT NULL,
++PRIMARY KEY (id)
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT, 
++parent_id INT,
++FOREIGN KEY (parent_id) 
++REFERENCES parent(id)
++ON UPDATE SET NULL
++ON DELETE SET NULL
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (1),(2);
++INSERT INTO child VALUES (1,1),(2,2);
++DELETE FROM parent WHERE id = 1;
++SELECT parent_id IS NULL FROM child WHERE id = 1;
++parent_id IS NULL
++1
++SELECT parent_id IS NULL FROM child WHERE id = 1;
++parent_id IS NULL
++1
++UPDATE parent SET id = 3 WHERE id = 2;
++SELECT parent_id IS NULL FROM child WHERE id = 2;
++parent_id IS NULL
++1
++SELECT parent_id IS NULL FROM child WHERE id = 2;
++parent_id IS NULL
++1
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/r/galera_ftwrl.result b/mysql-test/suite/galera/r/galera_ftwrl.result
+new file mode 100644
+index 0000000..c216b52
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ftwrl.result
+@@ -0,0 +1,16 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT1S";
++FLUSH TABLES WITH READ LOCK;
++INSERT INTO t1 VALUES (1);
++SHOW TABLES;
++ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++SELECT * FROM t1;
++ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++UNLOCK TABLES;
++SHOW TABLES;
++Tables_in_test
++t1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_fulltext.result b/mysql-test/suite/galera/r/galera_fulltext.result
+new file mode 100644
+index 0000000..7257769
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_fulltext.result
+@@ -0,0 +1,26 @@
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(100), FULLTEXT (f2)) ENGINE=InnoDB;
++SELECT COUNT(*) = 13 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name LIKE 'test/%';
++COUNT(*) = 13
++1
++INSERT INTO t1 (f2) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
++COUNT(f2) = 10000
++1
++UPDATE t1 SET f2 = 'abcdefjhk';
++SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('abcdefjhk');
++COUNT(f2) = 10000
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 VARCHAR(100), FULLTEXT (f1)) ENGINE=InnoDB;
++INSERT INTO t1 (f1) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3;
++SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('foobarbaz');
++COUNT(f1) = 1000
++1
++UPDATE t1 SET f1 = 'abcdefjhk';
++SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('abcdefjhk');
++COUNT(f1) = 1000
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_gcs_fc_limit.result b/mysql-test/suite/galera/r/galera_gcs_fc_limit.result
+new file mode 100644
+index 0000000..99c710f
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_gcs_fc_limit.result
+@@ -0,0 +1,17 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
++FLUSH TABLES WITH READ LOCK;
++INSERT INTO t1 VALUES (2);
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++INSERT INTO t1 VALUES (5);
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'query end' AND INFO = 'INSERT INTO t1 VALUES (5)';
++COUNT(*) = 1
++1
++UNLOCK TABLES;
++INSERT INTO t1 VALUES (6);
++SELECT COUNT(*) = 6 FROM t1;
++COUNT(*) = 6
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result b/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result
+new file mode 100644
+index 0000000..606cb54
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result
+@@ -0,0 +1,15 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
++CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 VARCHAR(512) UNIQUE) ENGINE=InnoDB;
++INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++INSERT INTO t2 VALUES (REPEAT('x', 512));
++SELECT COUNT(*) = 10000 FROM t1;
++COUNT(*) = 10000
++1
++SELECT LENGTH(f1) = 512 FROM t2 WHERE f1 = REPEAT('x', 512);
++LENGTH(f1) = 512
++1
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_gtid.result b/mysql-test/suite/galera/r/galera_gtid.result
+new file mode 100644
+index 0000000..50d561d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_gtid.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY);
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 2;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++COUNT(*) = 1
++1
++gtid_executed_equal
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_insert_ignore.result b/mysql-test/suite/galera/r/galera_insert_ignore.result
+new file mode 100644
+index 0000000..2d6e38e
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_insert_ignore.result
+@@ -0,0 +1,48 @@
++SET GLOBAL wsrep_sync_wait = 7;
++SET GLOBAL wsrep_sync_wait = 7;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++INSERT IGNORE INTO t1 VALUES (1), (2);
++SELECT * FROM t1;
++f1
++1
++2
++SELECT * FROM t1;
++f1
++1
++2
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (0), (2), (3);
++INSERT IGNORE INTO t1 SELECT f1 FROM t2;
++SELECT * FROM t1;
++f1
++0
++1
++2
++3
++SELECT * FROM t1;
++f1
++0
++1
++2
++3
++CREATE TABLE t3 (f1 INTEGER UNIQUE) Engine=InnoDB;
++INSERT INTO t3 VALUES (NULL);
++INSERT IGNORE INTO t3 VALUES (1), (NULL), (2);
++SELECT * FROM t3;
++f1
++NULL
++NULL
++1
++2
++SELECT * FROM t3;
++f1
++NULL
++NULL
++1
++2
++SET GLOBAL wsrep_sync_wait = (SELECT @@wsrep_sync_wait);
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++SET GLOBAL wsrep_sync_wait = (SELECT @@wsrep_sync_wait);
+diff --git a/mysql-test/suite/galera/r/galera_insert_multi.result b/mysql-test/suite/galera/r/galera_insert_multi.result
+new file mode 100644
+index 0000000..3371778
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_insert_multi.result
+@@ -0,0 +1,58 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1),(2);
++INSERT INTO t1 VALUES (3),(4);
++SELECT COUNT(*) = 4 FROM t1;
++COUNT(*) = 4
++1
++SELECT COUNT(*) = 4 FROM t1;
++COUNT(*) = 4
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER, KEY (f1)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1),(1);
++INSERT INTO t1 VALUES (2),(2);
++SELECT COUNT(*) = 4 FROM t1;
++COUNT(*) = 4
++1
++SELECT COUNT(*) = 4 FROM t1;
++COUNT(*) = 4
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (1);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1), (2);
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (2), (1);
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++ROLLBACK;
++INSERT INTO t1 VALUES (1), (2);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1), (2);
++START TRANSACTION;
++INSERT INTO t1 VALUES (2), (1);
++ROLLBACK;
++COMMIT;
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result b/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result
+new file mode 100644
+index 0000000..5421b23
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result
+@@ -0,0 +1,184 @@
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/r/galera_ist_mysqldump.result b/mysql-test/suite/galera/r/galera_ist_mysqldump.result
+new file mode 100644
+index 0000000..4b5a8fe
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ist_mysqldump.result
+@@ -0,0 +1,284 @@
++Setting SST method to mysqldump ...
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++SET GLOBAL wsrep_sst_auth = 'sst:sst';
++SET GLOBAL wsrep_sst_method = 'mysqldump';
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++DROP USER sst;
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
++CALL mtr.add_suppression("InnoDB: New log files created");
++CALL mtr.add_suppression("InnoDB: Creating foreign key constraint system tables");
++CALL mtr.add_suppression("Can't open and lock time zone table");
++CALL mtr.add_suppression("Can't open and lock privilege tables");
++CALL mtr.add_suppression("Info table is not ready to be used");
++CALL mtr.add_suppression("Native table .* has the wrong structure");
+diff --git a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
+new file mode 100644
+index 0000000..f7a1386
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
+@@ -0,0 +1,43 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
++INSERT INTO t1 VALUES (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'),(6, 'a');
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++UPDATE t1 SET f2 = 'b' WHERE f1 > 1;
++UPDATE t1 SET f2 = 'c' WHERE f1 > 2;
++SET GLOBAL wsrep_provider_options = 'dbug=d,recv_IST_after_apply_trx';
++SET SESSION wsrep_sync_wait = 0;
++Loading wsrep_provider ...
++SHOW STATUS LIKE 'wsrep_debug_sync_waiters';
++Variable_name Value
++wsrep_debug_sync_waiters      recv_IST_after_apply_trx
++UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
++CREATE TABLE t2 (f1 INTEGER);
++UPDATE t1 SET f2 = 'e' WHERE f1 > 4;
++CREATE TABLE t3 (f1 INTEGER);
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++UPDATE t1 SET f2 = 'f' WHERE f1 > 5;
++SELECT * FROM t1;
++f1    f2
++1     a
++2     b
++3     c
++4     d
++5     e
++6     f
++SELECT * FROM t1;
++f1    f2
++1     a
++2     b
++3     c
++4     d
++5     e
++6     f
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t3;
++COUNT(*) = 0
++1
++DROP TABLE t1, t2, t3;
+diff --git a/mysql-test/suite/galera/r/galera_ist_rsync.result b/mysql-test/suite/galera/r/galera_ist_rsync.result
+new file mode 100644
+index 0000000..175e744
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ist_rsync.result
+@@ -0,0 +1,357 @@
++Performing State Transfer on a server that has been temporarily disconnected
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Loading wsrep provider ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/r/galera_ist_xtrabackup-v2.result b/mysql-test/suite/galera/r/galera_ist_xtrabackup-v2.result
+new file mode 100644
+index 0000000..175e744
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ist_xtrabackup-v2.result
+@@ -0,0 +1,357 @@
++Performing State Transfer on a server that has been temporarily disconnected
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Loading wsrep provider ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/r/galera_kill_ddl.result b/mysql-test/suite/galera/r/galera_kill_ddl.result
+new file mode 100644
+index 0000000..8dd3649
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_kill_ddl.result
+@@ -0,0 +1,11 @@
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++Killing server ...
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1';
++COUNT(*) = 2
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_kill_largechanges.result b/mysql-test/suite/galera/r/galera_kill_largechanges.result
+new file mode 100644
+index 0000000..a37056a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_kill_largechanges.result
+@@ -0,0 +1,14 @@
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
++CREATE TABLE t1 (f1 VARCHAR(128)) ENGINE=InnoDB;
++Killing server ...
++INSERT INTO t1 SELECT REPEAT('a', 128) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
++SELECT COUNT(*) = 1000000 FROM t1;
++COUNT(*) = 1000000
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_kill_nochanges.result b/mysql-test/suite/galera/r/galera_kill_nochanges.result
+new file mode 100644
+index 0000000..accace9
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_kill_nochanges.result
+@@ -0,0 +1,9 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_kill_smallchanges.result b/mysql-test/suite/galera/r/galera_kill_smallchanges.result
+new file mode 100644
+index 0000000..8409740
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_kill_smallchanges.result
+@@ -0,0 +1,11 @@
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++Killing server ...
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_lock_table.result b/mysql-test/suite/galera/r/galera_lock_table.result
+new file mode 100644
+index 0000000..16e9037
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_lock_table.result
+@@ -0,0 +1,21 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
++LOCK TABLE t1 READ;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++SET SESSION wsrep_sync_wait=0;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++UNLOCK TABLES;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_log_bin.result b/mysql-test/suite/galera/r/galera_log_bin.result
+new file mode 100644
+index 0000000..9a8513d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_log_bin.result
+@@ -0,0 +1,53 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++CREATE TABLE t2 (id INT) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (1);
++INSERT INTO t2 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 2 FROM t2;
++COUNT(*) = 2
++1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++FLUSH LOGS;
++SHOW BINLOG EVENTS IN '0.000002' FROM 120;
++Log_name      Pos     Event_type      Server_id       End_log_pos     Info
++0.000002      120     Query   1       244     use `test`; CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB
++0.000002      244     Query   1       321     BEGIN
++0.000002      321     Table_map       1       366     table_id: 103 (test.t1)
++0.000002      366     Write_rows      1       406     table_id: 103 flags: STMT_END_F
++0.000002      406     Xid     1       437     COMMIT /* xid=2 */
++0.000002      437     Query   1       549     use `test`; CREATE TABLE t2 (id INT) ENGINE=InnoDB
++0.000002      549     Query   1       626     BEGIN
++0.000002      626     Table_map       1       671     table_id: 104 (test.t2)
++0.000002      671     Write_rows      1       711     table_id: 104 flags: STMT_END_F
++0.000002      711     Xid     1       742     COMMIT /* xid=4 */
++0.000002      742     Query   1       819     BEGIN
++0.000002      819     Table_map       1       864     table_id: 104 (test.t2)
++0.000002      864     Write_rows      1       904     table_id: 104 flags: STMT_END_F
++0.000002      904     Xid     1       935     COMMIT /* xid=5 */
++0.000002      935     Query   1       1045    use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER
++0.000002      1045    Rotate  1       1084    0.000003;pos=4
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SHOW BINLOG EVENTS IN '0.000001' FROM 120;
++Log_name      Pos     Event_type      Server_id       End_log_pos     Info
++0.000001      120     Query   1       244     use `test`; CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB
++0.000001      244     Query   1       312     BEGIN
++0.000001      312     Table_map       1       357     table_id: 81 (test.t1)
++0.000001      357     Write_rows      1       397     table_id: 81 flags: STMT_END_F
++0.000001      397     Xid     1       428     COMMIT /* xid=2 */
++0.000001      428     Query   1       540     use `test`; CREATE TABLE t2 (id INT) ENGINE=InnoDB
++0.000001      540     Query   1       608     BEGIN
++0.000001      608     Table_map       1       653     table_id: 82 (test.t2)
++0.000001      653     Write_rows      1       693     table_id: 82 flags: STMT_END_F
++0.000001      693     Xid     1       724     COMMIT /* xid=4 */
++0.000001      724     Query   1       792     BEGIN
++0.000001      792     Table_map       1       837     table_id: 82 (test.t2)
++0.000001      837     Write_rows      1       877     table_id: 82 flags: STMT_END_F
++0.000001      877     Xid     1       908     COMMIT /* xid=5 */
++0.000001      908     Query   1       1018    use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_log_output_csv.result b/mysql-test/suite/galera/r/galera_log_output_csv.result
+new file mode 100644
+index 0000000..07a7846
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_log_output_csv.result
+@@ -0,0 +1,21 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) > 0 FROM mysql.general_log;
++COUNT(*) > 0
++1
++SELECT 1 = 1 FROM t1;
++1 = 1
++1
++SELECT COUNT(*) = 1 FROM mysql.slow_log WHERE sql_text = 'SELECT 1 = 1 FROM t1';
++COUNT(*) = 1
++1
++SELECT COUNT(*) > 0 FROM mysql.general_log WHERE argument = 'CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB';
++COUNT(*) > 0
++1
++SELECT 2 = 2 FROM t1;
++2 = 2
++1
++SELECT COUNT(*) = 1 FROM mysql.slow_log WHERE sql_text = 'SELECT 2 = 2 FROM t1';
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_many_columns.result b/mysql-test/suite/galera/r/galera_many_columns.result
+new file mode 100644
+index 0000000..6fa574e
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_many_columns.result
+@@ -0,0 +1,32 @@
++INSERT INTO t1 (f1) VALUES (DEFAULT);
++SELECT f1 = 'ABC', f1017 = 'ABC' FROM t1;
++f1 = 'ABC'    f1017 = 'ABC'
++1     1
++UPDATE t1 SET f1 = 'XYZ', f1017 = 'XYZ' ;
++SELECT f1 = 'XYZ', f1017 = 'XYZ' FROM t1 WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++f1 = 'XYZ'    f1017 = 'XYZ'
++1     1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'KLM' WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'CDE' WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++ROLLBACK;
++ROLLBACK;
++START TRANSACTION;
++INSERT INTO t1 (f1, f1017) VALUES ('BCE','BCE');
++INSERT INTO t1 (f1, f1017) VALUES ('CED','CED');
++INSERT INTO t1 (f1, f1017) VALUES ('EDF','EDF');
++INSERT INTO t1 (f1, f1017) VALUES ('FED','FED');
++ROLLBACK;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_many_indexes.result b/mysql-test/suite/galera/r/galera_many_indexes.result
+new file mode 100644
+index 0000000..ab6eec5
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_many_indexes.result
+@@ -0,0 +1,123 @@
++CREATE TABLE t1 (f1 VARCHAR(767) PRIMARY KEY) ENGINE=InnoDB;
++CREATE UNIQUE INDEX i63 ON t1(f1);
++CREATE UNIQUE INDEX i62 ON t1(f1);
++CREATE UNIQUE INDEX i61 ON t1(f1);
++CREATE UNIQUE INDEX i60 ON t1(f1);
++CREATE UNIQUE INDEX i59 ON t1(f1);
++CREATE UNIQUE INDEX i58 ON t1(f1);
++CREATE UNIQUE INDEX i57 ON t1(f1);
++CREATE UNIQUE INDEX i56 ON t1(f1);
++CREATE UNIQUE INDEX i55 ON t1(f1);
++CREATE UNIQUE INDEX i54 ON t1(f1);
++CREATE UNIQUE INDEX i53 ON t1(f1);
++CREATE UNIQUE INDEX i52 ON t1(f1);
++CREATE UNIQUE INDEX i51 ON t1(f1);
++CREATE UNIQUE INDEX i50 ON t1(f1);
++CREATE UNIQUE INDEX i49 ON t1(f1);
++CREATE UNIQUE INDEX i48 ON t1(f1);
++CREATE UNIQUE INDEX i47 ON t1(f1);
++CREATE UNIQUE INDEX i46 ON t1(f1);
++CREATE UNIQUE INDEX i45 ON t1(f1);
++CREATE UNIQUE INDEX i44 ON t1(f1);
++CREATE UNIQUE INDEX i43 ON t1(f1);
++CREATE UNIQUE INDEX i42 ON t1(f1);
++CREATE UNIQUE INDEX i41 ON t1(f1);
++CREATE UNIQUE INDEX i40 ON t1(f1);
++CREATE UNIQUE INDEX i39 ON t1(f1);
++CREATE UNIQUE INDEX i38 ON t1(f1);
++CREATE UNIQUE INDEX i37 ON t1(f1);
++CREATE UNIQUE INDEX i36 ON t1(f1);
++CREATE UNIQUE INDEX i35 ON t1(f1);
++CREATE UNIQUE INDEX i34 ON t1(f1);
++CREATE UNIQUE INDEX i33 ON t1(f1);
++CREATE UNIQUE INDEX i32 ON t1(f1);
++CREATE UNIQUE INDEX i31 ON t1(f1);
++CREATE UNIQUE INDEX i30 ON t1(f1);
++CREATE UNIQUE INDEX i29 ON t1(f1);
++CREATE UNIQUE INDEX i28 ON t1(f1);
++CREATE UNIQUE INDEX i27 ON t1(f1);
++CREATE UNIQUE INDEX i26 ON t1(f1);
++CREATE UNIQUE INDEX i25 ON t1(f1);
++CREATE UNIQUE INDEX i24 ON t1(f1);
++CREATE UNIQUE INDEX i23 ON t1(f1);
++CREATE UNIQUE INDEX i22 ON t1(f1);
++CREATE UNIQUE INDEX i21 ON t1(f1);
++CREATE UNIQUE INDEX i20 ON t1(f1);
++CREATE UNIQUE INDEX i19 ON t1(f1);
++CREATE UNIQUE INDEX i18 ON t1(f1);
++CREATE UNIQUE INDEX i17 ON t1(f1);
++CREATE UNIQUE INDEX i16 ON t1(f1);
++CREATE UNIQUE INDEX i15 ON t1(f1);
++CREATE UNIQUE INDEX i14 ON t1(f1);
++CREATE UNIQUE INDEX i13 ON t1(f1);
++CREATE UNIQUE INDEX i12 ON t1(f1);
++CREATE UNIQUE INDEX i11 ON t1(f1);
++CREATE UNIQUE INDEX i10 ON t1(f1);
++CREATE UNIQUE INDEX i9 ON t1(f1);
++CREATE UNIQUE INDEX i8 ON t1(f1);
++CREATE UNIQUE INDEX i7 ON t1(f1);
++CREATE UNIQUE INDEX i6 ON t1(f1);
++CREATE UNIQUE INDEX i5 ON t1(f1);
++CREATE UNIQUE INDEX i4 ON t1(f1);
++CREATE UNIQUE INDEX i3 ON t1(f1);
++CREATE UNIQUE INDEX i2 ON t1(f1);
++CREATE UNIQUE INDEX i1 ON t1(f1);
++INSERT INTO t1 VALUES (REPEAT('a', 767));
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT LENGTH(f1) = 767 FROM t1;
++LENGTH(f1) = 767
++1
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (PRIMARY) WHERE f1 = REPEAT('a', 767);
++id    select_type     table   type    possible_keys   key     key_len ref     rows    Extra
++1     SIMPLE  t1      const   PRIMARY PRIMARY 769     const   1       Using index
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (PRIMARY) WHERE f1 = REPEAT('a', 767);
++COUNT(*) = 1
++1
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i1) WHERE f1 = REPEAT('a', 767);
++id    select_type     table   type    possible_keys   key     key_len ref     rows    Extra
++1     SIMPLE  t1      const   i1      i1      769     const   1       Using index
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i1) WHERE f1 = REPEAT('a', 767);
++COUNT(*) = 1
++1
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i63) WHERE f1 = REPEAT('a', 767);
++id    select_type     table   type    possible_keys   key     key_len ref     rows    Extra
++1     SIMPLE  t1      const   i63     i63     769     const   1       Using index
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i63) WHERE f1 = REPEAT('a', 767);
++COUNT(*) = 1
++1
++INSERT INTO t1 VALUES (REPEAT('b', 767));
++ANALYZE TABLE t1;
++Table Op      Msg_type        Msg_text
++test.t1       analyze status  OK
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++ANALYZE TABLE t1;
++Table Op      Msg_type        Msg_text
++test.t1       analyze status  OK
++DELETE FROM t1 WHERE f1 = REPEAT('b', 767);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++INSERT INTO t1 (f1) VALUES (REPEAT('c', 767));
++ROLLBACK;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++START TRANSACTION;
++SET AUTOCOMMIT=OFF;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++START TRANSACTION;
++START TRANSACTION;
++UPDATE t1 SET f1 = REPEAT('e', 767);
++UPDATE t1 SET f1 = REPEAT('f', 767);
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_many_rows.result b/mysql-test/suite/galera/r/galera_many_rows.result
+new file mode 100644
+index 0000000..6ec0add
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_many_rows.result
+@@ -0,0 +1,41 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SELECT COUNT(*) = 100000 FROM t1;
++COUNT(*) = 100000
++1
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++UPDATE t1 SET f2 = 1;
++SELECT COUNT(*) = 200000 FROM t1 WHERE f2 = 1;
++COUNT(*) = 200000
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++ROLLBACK;
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 2;
++ROLLBACK;
++START TRANSACTION;
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++UPDATE t1 SET f2 = 3;
++START TRANSACTION;
++UPDATE t1 SET f2 = 4;
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_many_tables_nopk.result b/mysql-test/suite/galera/r/galera_many_tables_nopk.result
+new file mode 100644
+index 0000000..7a4f364
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_many_tables_nopk.result
+@@ -0,0 +1,17 @@
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++COMMIT;
++CREATE TABLE sum_table (f1 INTEGER);
++SELECT SUM(f1) = 1000 FROM sum_table;
++SUM(f1) = 1000
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1000 SET f1 = 3;
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP SCHEMA test;
++CREATE SCHEMA test;
+diff --git a/mysql-test/suite/galera/r/galera_many_tables_pk.result b/mysql-test/suite/galera/r/galera_many_tables_pk.result
+new file mode 100644
+index 0000000..6b6899d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_many_tables_pk.result
+@@ -0,0 +1,20 @@
++SELECT COUNT(*) = 1000 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't%';
++COUNT(*) = 1000
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++COMMIT;
++CREATE TABLE sum_table (f1 INTEGER);
++SELECT SUM(f1) = 1000 FROM sum_table;
++SUM(f1) = 1000
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1000 SET f1 = 3;
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP SCHEMA test;
++CREATE SCHEMA test;
+diff --git a/mysql-test/suite/galera/r/galera_migrate.result b/mysql-test/suite/galera/r/galera_migrate.result
+new file mode 100644
+index 0000000..7c92d66
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_migrate.result
+@@ -0,0 +1,79 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++INSERT INTO t1 VALUES (2);
++START SLAVE USER='root';
++Warnings:
++Note  1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++SET GLOBAL wsrep_cluster_address='gcomm://';
++INSERT INTO t1 VALUES (5);
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 1
++1
++INSERT INTO t1 VALUES (6);
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++SET GLOBAL wsrep_sst_auth = 'sst:sst';
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++STOP SLAVE;
++RESET SLAVE ALL;
++STOP SLAVE;
++RESET SLAVE ALL;
++INSERT INTO t1 VALUES (7);
++INSERT INTO t1 VALUES (8);
++SELECT COUNT(*) = 8 FROM t1;
++COUNT(*) = 8
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SELECT COUNT(*) = 8 FROM t1;
++COUNT(*) = 8
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
++DROP TABLE t1;
++SET GLOBAL wsrep_provider = 'none';
++SET GLOBAL wsrep_sst_auth = '';
++SET GLOBAL wsrep_provider_options = '';
++DROP TABLE t1;
++DROP USER sst;
++SET GLOBAL wsrep_provider = 'none';
++SET GLOBAL wsrep_sst_method = 'rsync';
++SET GLOBAL wsrep_provider_options = '';
++SET GLOBAL wsrep_sst_receive_address = 'AUTO';
++DROP TABLE t1;
++DROP USER sst;
++CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
+diff --git a/mysql-test/suite/galera/r/galera_multi_database.result b/mysql-test/suite/galera/r/galera_multi_database.result
+new file mode 100644
+index 0000000..a04eb48
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_multi_database.result
+@@ -0,0 +1,28 @@
++CREATE DATABASE d1;
++CREATE TABLE d1.t1(f1 INTEGER) ENGINE=InnoDB;
++CREATE DATABASE d2;
++CREATE TABLE d2.t1(f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO d1.t1 VALUES (1);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO d2.t1 VALUES (1);
++COMMIT;
++COMMIT;
++SELECT COUNT(*) = 1 FROM d1.t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM d2.t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM d1.t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM d2.t1;
++COUNT(*) = 1
++1
++DROP TABLE d1.t1;
++DROP TABLE d2.t1;
++DROP DATABASE d1;
++DROP DATABASE d2;
+diff --git a/mysql-test/suite/galera/r/galera_myisam_autocommit.result b/mysql-test/suite/galera/r/galera_myisam_autocommit.result
+new file mode 100644
+index 0000000..3f8d93b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_myisam_autocommit.result
+@@ -0,0 +1,24 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (2), (3);
++INSERT INTO t1 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM;
++INSERT INTO t2 VALUES (1);
++INSERT INTO t2 VALUES (2), (3);
++INSERT INTO t2 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++INSERT INTO t2 VALUES (6), (1);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++UPDATE t1 SET f1 = 9;
++UPDATE t2 SET f1 = 9 WHERE f1 = 1;
++DELETE FROM t1 WHERE f1 = 9;
++DELETE FROM t2 WHERE f1 = 9;
++TRUNCATE TABLE t1;
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_myisam_transactions.result b/mysql-test/suite/galera/r/galera_myisam_transactions.result
+new file mode 100644
+index 0000000..284f92b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_myisam_transactions.result
+@@ -0,0 +1,34 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
++CREATE TABLE t3 (f1 INTEGER) ENGINE=MyISAM;
++CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t3 VALUES (NEW.f1);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++COMMIT;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++ROLLBACK;
++Warnings:
++Warning       1196    Some non-transactional changed tables couldn't be rolled back
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++DROP TABLE t1, t2, t3;
+diff --git a/mysql-test/suite/galera/r/galera_nopk_bit.result b/mysql-test/suite/galera/r/galera_nopk_bit.result
+new file mode 100644
+index 0000000..5723dac
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_nopk_bit.result
+@@ -0,0 +1,27 @@
++CREATE TABLE t1 (f1 BIT) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),(0),(b'1');
++SELECT f1 IS NULL, f1 = b'1' FROM t1;
++f1 IS NULL    f1 = b'1'
++1     NULL
++0     0
++0     1
++DELETE FROM t1 WHERE f1 = b'1';
++UPDATE t1 SET f1 = b'1' WHERE f1 IS NULL;
++UPDATE t1 SET f1 = 1 WHERE f1 = b'0';
++SELECT f1 IS NULL, f1 = b'1' FROM t1;
++f1 IS NULL    f1 = b'1'
++0     1
++0     1
++CREATE TABLE t2 (f1 BIT) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (NULL);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 0 WHERE f1 IS NULL;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 1 WHERE f1 IS NULL;
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_nopk_blob.result b/mysql-test/suite/galera/r/galera_nopk_blob.result
+new file mode 100644
+index 0000000..7491b71
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_nopk_blob.result
+@@ -0,0 +1,27 @@
++CREATE TABLE t1 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),('abc');
++SELECT f1 FROM t1;
++f1
++NULL
++abc
++DELETE FROM t1 WHERE f1 IS NULL;
++UPDATE t1 SET f1 = 'xyz' WHERE f1 = 'abc';
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT f1 = 'abc' FROM t1;
++f1 = 'abc'
++0
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (NULL);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'abc' WHERE f1 IS NULL;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'xyz' WHERE f1 IS NULL;
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_nopk_large_varchar.result b/mysql-test/suite/galera/r/galera_nopk_large_varchar.result
+new file mode 100644
+index 0000000..abca81e
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_nopk_large_varchar.result
+@@ -0,0 +1,30 @@
++CREATE TABLE t1 (f1 VARCHAR(8000)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),(CONCAT(REPEAT('x', 7999), 'a'));
++SELECT LENGTH(f1) FROM t1;
++LENGTH(f1)
++NULL
++8000
++DELETE FROM t1 WHERE f1 IS NULL;
++UPDATE t1 SET f1 = CONCAT(REPEAT('x', 7999), 'b') WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT LENGTH(f1) = 8000 FROM t1;
++LENGTH(f1) = 8000
++1
++SELECT f1 = CONCAT(REPEAT('x', 7999), 'b') FROM t1;
++f1 = CONCAT(REPEAT('x', 7999), 'b')
++1
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (CONCAT(REPEAT('x', 7999), 'a'));
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'abc' WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'xyz' WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_nopk_unicode.result b/mysql-test/suite/galera/r/galera_nopk_unicode.result
+new file mode 100644
+index 0000000..68d049a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_nopk_unicode.result
+@@ -0,0 +1,24 @@
++CREATE TABLE t1 (
++f1 VARCHAR(255),
++KEY (f1)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++INSERT INTO t1 VALUES ('текст');
++SELECT f1 = 'текст' FROM t1;
++f1 = 'текст'
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст2';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст3';
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SELECT f1 = 'текст2' FROM t1;
++f1 = 'текст2'
++1
++SELECT f1 = 'текст2' FROM t1 WHERE f1 = 'текст2';
++f1 = 'текст2'
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result b/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result
+new file mode 100644
+index 0000000..85ba022
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result
+@@ -0,0 +1,33 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
++SET GLOBAL wsrep_slave_threads = 2;
++LOCK TABLE t1 READ;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++SET SESSION wsrep_sync_wait=0;
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%applied write set%';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Waiting for table level lock%';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++UNLOCK TABLES;
++SET SESSION wsrep_sync_wait = 7;;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 2  FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committed%';
++COUNT(*) = 2
++1
++SET GLOBAL wsrep_slave_threads = 1;;
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result b/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result
+new file mode 100644
+index 0000000..1f163f4
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result
+@@ -0,0 +1,18 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++SET GLOBAL wsrep_slave_threads = 4;
++INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++SELECT COUNT(*) = 30000 FROM t1;
++COUNT(*) = 30000
++1
++SELECT COUNT(DISTINCT f1) = 30000 FROM t1;
++COUNT(DISTINCT f1) = 30000
++1
++SELECT COUNT(*) = 5 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++COUNT(*) = 5
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result b/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result
+new file mode 100644
+index 0000000..05ce328
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result
+@@ -0,0 +1,15 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++SET GLOBAL wsrep_slave_threads = 4;
++SELECT COUNT(*) = 20000 FROM t1;
++COUNT(*) = 20000
++1
++SELECT COUNT(DISTINCT f1) = 20000 FROM t1;
++COUNT(DISTINCT f1) = 20000
++1
++SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
++COUNT(*) = 4
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_parallel_simple.result b/mysql-test/suite/galera/r/galera_parallel_simple.result
+new file mode 100644
+index 0000000..294a94b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_parallel_simple.result
+@@ -0,0 +1,27 @@
++CREATE TABLE t1 (id INT) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT) ENGINE=InnoDB;
++SET GLOBAL wsrep_slave_threads = 2;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++SELECT COUNT(*) = 10 FROM t1;
++COUNT(*) = 10
++0
++SELECT COUNT(*) = 10 FROM t2;
++COUNT(*) = 10
++0
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'committed%';
++COUNT(*) = 2
++1
++SET GLOBAL wsrep_slave_threads = 1;;
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_pc_ignore_sb.result b/mysql-test/suite/galera/r/galera_pc_ignore_sb.result
+new file mode 100644
+index 0000000..5fcccfe
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_pc_ignore_sb.result
+@@ -0,0 +1,12 @@
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++Killing server ...
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++DROP TABLE t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 1
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SET GLOBAL wsrep_cluster_address = '';
+diff --git a/mysql-test/suite/galera/r/galera_pk_bigint_signed.result b/mysql-test/suite/galera/r/galera_pk_bigint_signed.result
+new file mode 100644
+index 0000000..a307599
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_pk_bigint_signed.result
+@@ -0,0 +1,26 @@
++CREATE TABLE t1 (f1 BIGINT SIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES
++(-9223372036854775808, 'min'),
++(9223372036854775807, 'max')
++;
++SELECT * FROM t1;
++f1    f2
++-9223372036854775808  min
++9223372036854775807   max
++UPDATE t1 SET f2 = CONCAT(f2, '_');
++SELECT * FROM t1;
++f1    f2
++-9223372036854775808  min_
++9223372036854775807   max_
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'foo' WHERE f1 = -9223372036854775808;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'bar' WHERE f1 = -9223372036854775808;
++COMMIT;
++SET AUTOCOMMIT=ON;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SET AUTOCOMMIT=ON;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result b/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result
+new file mode 100644
+index 0000000..441926e
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result
+@@ -0,0 +1,23 @@
++CREATE TABLE t1 (f1 BIGINT UNSIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES
++(18446744073709551615, 'max')
++;
++SELECT f1 = 18446744073709551615 FROM t1;
++f1 = 18446744073709551615
++1
++UPDATE t1 SET f2 = CONCAT(f2, '_');
++SELECT f1 = 18446744073709551615 FROM t1;
++f1 = 18446744073709551615
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'foo' WHERE f1 = 18446744073709551615;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'bar' WHERE f1 = 18446744073709551615;
++COMMIT;
++SET AUTOCOMMIT=ON;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SET AUTOCOMMIT=ON;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_query_cache.result b/mysql-test/suite/galera/r/galera_query_cache.result
+new file mode 100644
+index 0000000..502d8a5
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_query_cache.result
+@@ -0,0 +1,57 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++RESET QUERY CACHE;
++FLUSH STATUS;
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++1
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++VARIABLE_VALUE = 1
++1
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++1
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++VARIABLE_VALUE = 1
++1
++INSERT INTO t1 VALUES (2);
++FLUSH STATUS;
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++VARIABLE_VALUE = 0
++1
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++2
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++VARIABLE_VALUE = 1
++1
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++VARIABLE_VALUE = 0
++1
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++2
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++VARIABLE_VALUE = 1
++1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++FLUSH STATUS;
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++VARIABLE_VALUE = 0
++1
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++2
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++VARIABLE_VALUE = 1
++1
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++VARIABLE_VALUE = 0
++1
++SELECT COUNT(*) FROM t1;
++COUNT(*)
++2
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++VARIABLE_VALUE = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_read_only.result b/mysql-test/suite/galera/r/galera_read_only.result
+new file mode 100644
+index 0000000..d2af386
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_read_only.result
+@@ -0,0 +1,8 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++SET GLOBAL read_only=TRUE;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SET GLOBAL read_only=FALSE;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result b/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result
+new file mode 100644
+index 0000000..4acf014
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result
+@@ -0,0 +1,18 @@
++SET GLOBAL wsrep_provider_options = 'repl.key_format=FLAT16';
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (123);
++CREATE TABLE t2 (f1 VARCHAR(256)) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (REPEAT('a', 256));
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 234;
++UPDATE t2 SET f1 = REPEAT('b', 256);
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 234;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = REPEAT('b', 256);
++COUNT(*) = 1
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_repl_max_ws_size.result b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
+new file mode 100644
+index 0000000..6e1054c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB;
++SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512';
++INSERT INTO t1 VALUES (REPEAT('a', 512));
++ERROR HY000: Got error 5 during COMMIT
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++CALL mtr.add_suppression("WSREP: Maximum writeset size exceeded by");
++CALL mtr.add_suppression("WSREP: transaction size exceeded");
+diff --git a/mysql-test/suite/galera/r/galera_restart_nochanges.result b/mysql-test/suite/galera/r/galera_restart_nochanges.result
+new file mode 100644
+index 0000000..accace9
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_restart_nochanges.result
+@@ -0,0 +1,9 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_rsu_add_pk.result b/mysql-test/suite/galera/r/galera_rsu_add_pk.result
+new file mode 100644
+index 0000000..3d8677d
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_rsu_add_pk.result
+@@ -0,0 +1,26 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;;
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET GLOBAL wsrep_OSU_method = "TOI";
++INSERT INTO t1 (f1) SELECT 200000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SELECT COUNT(*) = 300000 FROM t1;
++COUNT(*) = 300000
++1
++SELECT MAX(f1) =  299999 FROM t1;
++MAX(f1) =  299999
++1
++SELECT COUNT(*) = 300000 FROM t1;
++COUNT(*) = 300000
++1
++SELECT MAX(f1) =  299999 FROM t1;
++MAX(f1) =  299999
++1
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET GLOBAL wsrep_OSU_method = "TOI";
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_rsu_drop_pk.result b/mysql-test/suite/galera/r/galera_rsu_drop_pk.result
+new file mode 100644
+index 0000000..43b4b57
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_rsu_drop_pk.result
+@@ -0,0 +1,42 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;;
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 DROP PRIMARY KEY;
++SET GLOBAL wsrep_OSU_method = "TOI";
++INSERT INTO t1 (f1) SELECT 200000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SELECT COUNT(*) = 300000 FROM t1;
++COUNT(*) = 300000
++1
++SELECT MAX(f1) =  299999 FROM t1;
++MAX(f1) =  299999
++1
++SELECT COUNT(*) = 300000 FROM t1;
++COUNT(*) = 300000
++1
++SELECT MAX(f1) =  299999 FROM t1;
++MAX(f1) =  299999
++1
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 DROP PRIMARY KEY;
++SET GLOBAL wsrep_OSU_method = "TOI";
++INSERT INTO t1 (f1) VALUES (1);
++INSERT INTO t1 (f1) VALUES (10);
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 1;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 10;
++COUNT(*) = 2
++1
++INSERT INTO t1 (f1) VALUES (100);
++INSERT INTO t1 (f1) VALUES (1000);
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 100;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 1000;
++COUNT(*) = 2
++1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_rsu_error.result b/mysql-test/suite/galera/r/galera_rsu_error.result
+new file mode 100644
+index 0000000..1f9ea36
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_rsu_error.result
+@@ -0,0 +1,21 @@
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t1 VALUES (1), (1);
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++SET GLOBAL wsrep_OSU_method = "TOI";
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 't1';
++COUNT(*) = 0
++1
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 't1';
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(3) = 4 FROM t1;
++COUNT(3) = 4
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_rsu_simple.result b/mysql-test/suite/galera/r/galera_rsu_simple.result
+new file mode 100644
+index 0000000..169c4a5
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_rsu_simple.result
+@@ -0,0 +1,22 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET GLOBAL wsrep_OSU_method = "TOI";
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 1
++1
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++INSERT INTO t1 (f1) VALUES (2);
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_sbr.result b/mysql-test/suite/galera/r/galera_sbr.result
+new file mode 100644
+index 0000000..66ca8cf
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sbr.result
+@@ -0,0 +1,11 @@
++SET GLOBAL binlog_format = 'STATEMENT';
++SET SESSION binlog_format = 'STATEMENT';
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET SESSION binlog_format = 'MIXED';
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
++SET GLOBAL binlog_format = 'ROW';
+diff --git a/mysql-test/suite/galera/r/galera_sbr_binlog.result b/mysql-test/suite/galera/r/galera_sbr_binlog.result
+new file mode 100644
+index 0000000..66ca8cf
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sbr_binlog.result
+@@ -0,0 +1,11 @@
++SET GLOBAL binlog_format = 'STATEMENT';
++SET SESSION binlog_format = 'STATEMENT';
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET SESSION binlog_format = 'MIXED';
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
++SET GLOBAL binlog_format = 'ROW';
+diff --git a/mysql-test/suite/galera/r/galera_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result
+new file mode 100644
+index 0000000..6156150
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_split_brain.result
+@@ -0,0 +1,5 @@
++call mtr.add_suppression("WSREP: TO isolation failed for: ");
++Killing server ...
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SET GLOBAL wsrep_cluster_address = '';
+diff --git a/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result b/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result
+new file mode 100644
+index 0000000..89ab8d5
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++SET SESSION sql_log_bin = 0;
++INSERT INTO t1 VALUES (1);
++SET SESSION sql_log_bin = 1;
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_ssl.result b/mysql-test/suite/galera/r/galera_ssl.result
+new file mode 100644
+index 0000000..569c3c6
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_ssl.result
+@@ -0,0 +1,18 @@
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump.result b/mysql-test/suite/galera/r/galera_sst_mysqldump.result
+new file mode 100644
+index 0000000..1be2002
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sst_mysqldump.result
+@@ -0,0 +1,459 @@
++Setting SST method to mysqldump ...
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++SET GLOBAL wsrep_sst_auth = 'sst:sst';
++SET GLOBAL wsrep_sst_method = 'mysqldump';
++Performing State Transfer on a server that has been temporarily disconnected
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Loading wsrep provider ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that starts from a clean var directory
++This is accomplished by shutting down node #2 and removing its var directory before restarting it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++Cleaning var directory ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++DROP USER sst;
++CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
++CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
++CALL mtr.add_suppression("InnoDB: New log files created");
++CALL mtr.add_suppression("InnoDB: Creating foreign key constraint system tables");
++CALL mtr.add_suppression("Can't open and lock time zone table");
++CALL mtr.add_suppression("Can't open and lock privilege tables");
++CALL mtr.add_suppression("Info table is not ready to be used");
++CALL mtr.add_suppression("Native table .* has the wrong structure");
+diff --git a/mysql-test/suite/galera/r/galera_sst_rsync.result b/mysql-test/suite/galera/r/galera_sst_rsync.result
+new file mode 100644
+index 0000000..750d73b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sst_rsync.result
+@@ -0,0 +1,358 @@
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that starts from a clean var directory
++This is accomplished by shutting down node #2 and removing its var directory before restarting it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++Cleaning var directory ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result
+new file mode 100644
+index 0000000..750d73b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result
+@@ -0,0 +1,358 @@
++Performing State Transfer on a server that has been shut down cleanly and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that starts from a clean var directory
++This is accomplished by shutting down node #2 and removing its var directory before restarting it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Shutting down server ...
++Cleaning var directory ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Starting server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++INSERT INTO t1 VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++INSERT INTO t1 VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++INSERT INTO t1 VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
+diff --git a/mysql-test/suite/galera/r/galera_status_cluster.result b/mysql-test/suite/galera/r/galera_status_cluster.result
+new file mode 100644
+index 0000000..d7cf671
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_status_cluster.result
+@@ -0,0 +1,12 @@
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
+diff --git a/mysql-test/suite/galera/r/galera_status_local_state.result b/mysql-test/suite/galera/r/galera_status_local_state.result
+new file mode 100644
+index 0000000..65713f1
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_status_local_state.result
+@@ -0,0 +1,14 @@
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SET GLOBAL wsrep_desync = 1;
++SELECT VARIABLE_VALUE = 'Donor/Desynced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Donor/Desynced'
++1
++SET GLOBAL wsrep_desync = 0;
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
+diff --git a/mysql-test/suite/galera/r/galera_suspend_slave.result b/mysql-test/suite/galera/r/galera_suspend_slave.result
+new file mode 100644
+index 0000000..0290481
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_suspend_slave.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++Suspending node_2 ...
++INSERT INTO t1 VALUES (1);
++Got one of the listed errors
++Resuming node_2 ...
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result b/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result
+new file mode 100644
+index 0000000..f914153
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result
+@@ -0,0 +1,42 @@
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++ALTER TABLE t1 AUTO_INCREMENT = 1000;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++SELECT MIN(f1) >= 1000, COUNT(*) = 20, COUNT(DISTINCT f1) = 20 FROM t1 WHERE f1 >= 1000;
++MIN(f1) >= 1000       COUNT(*) = 20   COUNT(DISTINCT f1) = 20
++1     1       1
++SELECT MIN(f1) >= 1000, COUNT(*) = 20, COUNT(DISTINCT f1) = 20 FROM t1 WHERE f1 >= 1000;
++MIN(f1) >= 1000       COUNT(*) = 20   COUNT(DISTINCT f1) = 20
++1     1       1
++ALTER TABLE t1 AUTO_INCREMENT = 5;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++SELECT MIN(f1) >= 1000, COUNT(*) = 40, COUNT(DISTINCT f1) = 40 FROM t1 WHERE f1 >= 1000;
++MIN(f1) >= 1000       COUNT(*) = 40   COUNT(DISTINCT f1) = 40
++1     1       1
++SELECT MIN(f1) >= 1000, COUNT(*) = 40, COUNT(DISTINCT f1) = 40 FROM t1 WHERE f1 >= 1000;
++MIN(f1) >= 1000       COUNT(*) = 40   COUNT(DISTINCT f1) = 40
++1     1       1
++DROP TABLE t1;
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
++ALTER TABLE t1 AUTO_INCREMENT=100;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++SELECT MIN(f1) = 100, MAX(f1) = 119, COUNT(f1) = 20, COUNT(DISTINCT f1) = 20 FROM t1;
++MIN(f1) = 100 MAX(f1) = 119   COUNT(f1) = 20  COUNT(DISTINCT f1) = 20
++1     1       1       1
++SELECT MIN(f1) = 100, MAX(f1) = 119, COUNT(f1) = 20, COUNT(DISTINCT f1) = 20 FROM t1;
++MIN(f1) = 100 MAX(f1) = 119   COUNT(f1) = 20  COUNT(DISTINCT f1) = 20
++1     1       1       1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_error.result b/mysql-test/suite/galera/r/galera_toi_ddl_error.result
+new file mode 100644
+index 0000000..656e20b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ddl_error.result
+@@ -0,0 +1,19 @@
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 (f1) SELECT (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++INSERT INTO t1 (f1) SELECT MAX(f1) FROM t1;
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++ERROR 23000: Duplicate entry '111110' for key 'PRIMARY'
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) DEFAULT NULL
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) DEFAULT NULL
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result b/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result
+new file mode 100644
+index 0000000..81781fb
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result
+@@ -0,0 +1,31 @@
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE parent (
++id INT PRIMARY KEY AUTO_INCREMENT,
++f2 INTEGER,
++KEY (id)
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT PRIMARY KEY AUTO_INCREMENT,
++parent_id INT
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (DEFAULT, 0);
++INSERT INTO child (parent_id) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++INSERT INTO parent (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++INSERT INTO parent (f2) SELECT 2 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
++ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id);;
++SELECT COUNT(*) = 20001 FROM parent;
++COUNT(*) = 20001
++1
++SELECT COUNT(*) = 10000 FROM child;
++COUNT(*) = 10000
++1
++SELECT COUNT(*) = 20001 FROM parent;
++COUNT(*) = 20001
++1
++SELECT COUNT(*) = 10000 FROM child;
++COUNT(*) = 10000
++1
++DROP TABLE child;
++DROP TABLE parent;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_locking.result b/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
+new file mode 100644
+index 0000000..d961f04
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
+@@ -0,0 +1,39 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
++SET SESSION wsrep_sync_wait = 0;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++INSERT INTO t1 VALUES (1);
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t2 VALUES (1);
++COMMIT;;
++SET SESSION wsrep_sync_wait = 0;
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++SET DEBUG_SYNC= 'now SIGNAL continue';
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result b/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result
+new file mode 100644
+index 0000000..41e693c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result
+@@ -0,0 +1,23 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
++ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 (f1, f2) VALUES (DEFAULT, 123);;
++CREATE UNIQUE INDEX i1 ON t1(f2);;
++INSERT INTO t1 (f1, f2) VALUES (DEFAULT, 234);
++SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 3
++1
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 3
++1
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result b/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result
+new file mode 100644
+index 0000000..9dfa433
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result
+@@ -0,0 +1,35 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++INSERT INTO t1 VALUES (2, 3);
++ALTER TABLE t1 DROP COLUMN f2;
++INSERT INTO t1 VALUES (4);
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL,
++  PRIMARY KEY (`f1`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++SELECT * FROM t1 ORDER BY f1;
++f1
++1
++2
++4
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL,
++  PRIMARY KEY (`f1`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++SELECT * FROM t1 ORDER BY f1;
++f1
++1
++2
++4
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_toi_ftwrl.result b/mysql-test/suite/galera/r/galera_toi_ftwrl.result
+new file mode 100644
+index 0000000..594717c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_ftwrl.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++FLUSH TABLES WITH READ LOCK;
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++UNLOCK TABLES;
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `id` int(11) NOT NULL,
++  `f2` int(11) DEFAULT NULL,
++  PRIMARY KEY (`id`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result b/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result
+new file mode 100644
+index 0000000..eac50e8
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result
+@@ -0,0 +1,17 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (2);
++ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=EXCLUSIVE;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++INSERT INTO t1 VALUES (2, 2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++INSERT INTO t1 VALUES (3, 3);
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_toi_lock_shared.result b/mysql-test/suite/galera/r/galera_toi_lock_shared.result
+new file mode 100644
+index 0000000..36c3886
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_toi_lock_shared.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED;
++INSERT INTO t1 VALUES (2, 2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++INSERT INTO t1 VALUES (3, 3);
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_transaction_read_only.result b/mysql-test/suite/galera/r/galera_transaction_read_only.result
+new file mode 100644
+index 0000000..3cd1076
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_transaction_read_only.result
+@@ -0,0 +1,21 @@
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++COMMIT;
++wsrep_last_committed_diff
++1
++START TRANSACTION READ ONLY;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++COMMIT;
++wsrep_last_committed_diff
++1
++START TRANSACTION;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++COMMIT;
++wsrep_last_committed_diff
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_transaction_replay.result b/mysql-test/suite/galera/r/galera_transaction_replay.result
+new file mode 100644
+index 0000000..23ed87f
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_transaction_replay.result
+@@ -0,0 +1,30 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
++INSERT INTO t1 VALUES (1, 'a');
++INSERT INTO t1 VALUES (2, 'a');
++SET AUTOCOMMIT=ON;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
++SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
++f1    f2
++2     a
++SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_enter_sync';
++COMMIT;;
++SET SESSION wsrep_sync_wait = 0;
++UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
++SET GLOBAL wsrep_provider_options = 'dbug=';
++SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_enter_sync';
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
++COUNT(*) = 1
++1
++wsrep_local_replays
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_truncate.result b/mysql-test/suite/galera/r/galera_truncate.result
+new file mode 100644
+index 0000000..eeeb672
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_truncate.result
+@@ -0,0 +1,29 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 VALUES (1);
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++CREATE TABLE t2 (f1 VARCHAR(255)) Engine=InnoDB;
++INSERT INTO t2 VALUES ('abc');
++TRUNCATE TABLE t2;
++SELECT COUNT(*) = 0 FROM t2;
++COUNT(*) = 0
++1
++CREATE TABLE t3 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t3 VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
++CREATE TABLE t4 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB AUTO_INCREMENT=1234;
++INSERT INTO t4 VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
++TRUNCATE TABLE t3;
++TRUNCATE TABLE t4;
++SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t3', 't4');
++AUTO_INCREMENT = 1
++1
++1
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++DROP TABLE t4;
+diff --git a/mysql-test/suite/galera/r/galera_truncate_temporary.result b/mysql-test/suite/galera/r/galera_truncate_temporary.result
+new file mode 100644
+index 0000000..0bdc4e3
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_truncate_temporary.result
+@@ -0,0 +1,63 @@
++CREATE TEMPORARY TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 VALUES (1);
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT * FROM t1;
++ERROR 42S02: Table 'test.t1' doesn't exist
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (2);
++SELECT f1 = 2 FROM t1;
++f1 = 2
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT f1 = 1 FROM t1;
++f1 = 1
++1
++DROP TABLE t1;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT f1 = 1 FROM t1;
++f1 = 1
++1
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (2);
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT f1 = 2 FROM t1;
++f1 = 2
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_unicode_identifiers.result b/mysql-test/suite/galera/r/galera_unicode_identifiers.result
+new file mode 100644
+index 0000000..212c6c6
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_unicode_identifiers.result
+@@ -0,0 +1,46 @@
++SET GLOBAL wsrep_sync_wait = 7;
++SET GLOBAL wsrep_sync_wait = 7;
++CREATE DATABASE `database with space`;
++USE `database with space`;
++CREATE TABLE `table with space` (
++`column with space` INTEGER AUTO_INCREMENT PRIMARY KEY,
++`second column with space` INTEGER,
++UNIQUE `index name with space` (`second column with space`)
++);
++INSERT INTO `table with space` VALUES (DEFAULT, 1);
++CREATE DATABASE `база`;
++USE `база`;
++CREATE TABLE `таблица` (
++`първа_колона` INTEGER PRIMARY KEY,
++`втора_колона` INTEGER,
++UNIQUE `индекс` (`втора_колона`)
++);
++INSERT INTO `таблица` VALUES (1, 1);
++CREATE DATABASE `втора база`;
++USE `втора база`;
++CREATE TABLE `втора таблица` (
++`първа колона` INTEGER,
++`втора колона` INTEGER,
++KEY `първи индекс` (`първа колона`)
++);
++INSERT INTO `втора таблица` VALUES (1, 1);
++USE `database with space`;
++SELECT `second column with space` FROM `table with space`;
++second column with space
++1
++USE `база`;
++SELECT * FROM `таблица`;
++първа_колона       втора_колона
++1     1
++USE `втора база`;
++SELECT `втора колона` FROM `втора таблица`;
++втора колона
++1
++SET GLOBAL wsrep_sync_wait = (SELECT @@wsrep_sync_wait);
++DROP TABLE `database with space`.`table with space`;
++DROP TABLE `база`.`таблица`;
++DROP TABLE `втора база`.`втора таблица`;
++DROP DATABASE `database with space`;
++DROP DATABASE `база`;
++DROP DATABASE `втора база`;
++SET GLOBAL wsrep_sync_wait = (SELECT @@wsrep_sync_wait);
+diff --git a/mysql-test/suite/galera/r/galera_unicode_pk.result b/mysql-test/suite/galera/r/galera_unicode_pk.result
+new file mode 100644
+index 0000000..d59615b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_unicode_pk.result
+@@ -0,0 +1,31 @@
++CREATE TABLE t1 (
++f1 VARCHAR(255) PRIMARY KEY
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++INSERT INTO t1 VALUES ('текст');
++SELECT f1 = 'текст' FROM t1;
++f1 = 'текст'
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст2';
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст3';
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SELECT f1 = 'текст2' FROM t1;
++f1 = 'текст2'
++1
++SELECT f1 = 'текст2' FROM t1 WHERE f1 = 'текст2';
++f1 = 'текст2'
++1
++START TRANSACTION;
++INSERT INTO t1 VALUES ('текст4');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('текст4');
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++COMMIT;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_update_limit.result b/mysql-test/suite/galera/r/galera_update_limit.result
+new file mode 100644
+index 0000000..c26eb1c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_update_limit.result
+@@ -0,0 +1,17 @@
++CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 SELECT f1 FROM ten ORDER BY RAND();
++UPDATE IGNORE t1 SET f1 = FLOOR(1 + (RAND() * 10)) ORDER BY RAND() LIMIT 5;
++sum_matches
++1
++max_matches
++1
++DROP TABLE t1;
++CREATE TABLE t2 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t2 SELECT f1 FROM ten ORDER BY RAND();
++UPDATE IGNORE t2 SET f1 = FLOOR(1 + (RAND() * 10)) ORDER BY RAND() LIMIT 5;
++sum_matches
++1
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_v1_row_events.result b/mysql-test/suite/galera/r/galera_v1_row_events.result
+new file mode 100644
+index 0000000..a6ab623
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_v1_row_events.result
+@@ -0,0 +1,10 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result b/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result
+new file mode 100644
+index 0000000..92b69fb
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result
+@@ -0,0 +1,61 @@
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++SELECT @@auto_increment_increment = 1;
++@@auto_increment_increment = 1
++1
++SELECT @@auto_increment_offset = 1;
++@@auto_increment_offset = 1
++1
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, node VARCHAR(10)) ENGINE=InnoDB;
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL AUTO_INCREMENT,
++  `node` varchar(10) DEFAULT NULL,
++  PRIMARY KEY (`f1`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++SHOW CREATE TABLE t1;
++Table Create Table
++t1    CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL AUTO_INCREMENT,
++  `node` varchar(10) DEFAULT NULL,
++  PRIMARY KEY (`f1`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++SELECT @@auto_increment_increment = 1;
++@@auto_increment_increment = 1
++1
++SELECT @@auto_increment_offset = 1;
++@@auto_increment_offset = 1
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (node) VALUES ('node1');
++SELECT f1 FROM t1;
++f1
++1
++SELECT @@auto_increment_increment = 1;
++@@auto_increment_increment = 1
++1
++SELECT @@auto_increment_offset = 1;
++@@auto_increment_offset = 1
++1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (node) VALUES ('node2');
++SELECT f1 FROM t1;
++f1
++1
++COMMIT;
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++SELECT * FROM t1;
++f1    node
++1     node1
++SELECT * FROM t1;
++f1    node
++1     node1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result b/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result
+new file mode 100644
+index 0000000..8859209
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result
+@@ -0,0 +1,30 @@
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, node VARCHAR(10)) ENGINE=InnoDB;
++SELECT @@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size');
++@@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size')
++1
++SELECT @@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
++@@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1
++1
++INSERT INTO t1 VALUES (DEFAULT, 'node1');;
++INSERT INTO t1 VALUES (DEFAULT, 'node2');;
++SELECT @@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size');
++@@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size')
++1
++SELECT @@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
++@@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1
++1
++INSERT INTO t1 VALUES (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2');;
++INSERT INTO t1 VALUES (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1');;
++SELECT COUNT(*) = 22 FROM t1;
++COUNT(*) = 22
++1
++SELECT COUNT(DISTINCT f1) = 22 FROM t1;
++COUNT(DISTINCT f1) = 22
++1
++SELECT COUNT(*) = 22 FROM t1;
++COUNT(*) = 22
++1
++SELECT COUNT(DISTINCT f1) = 22 FROM t1;
++COUNT(DISTINCT f1) = 22
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result
+new file mode 100644
+index 0000000..35dabb7
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result
+@@ -0,0 +1,21 @@
++SET GLOBAL wsrep_certify_nonPK = OFF;
++SET GLOBAL wsrep_certify_nonPK = OFF;
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB /* Table has no primary key */;
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1), (2);
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++INSERT INTO t2 VALUES (1), (2);
++UPDATE t2 SET f1 = 3 WHERE f1 = 1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 2 FROM t2;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 3;
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_certify_nonPK = 1;
++SET GLOBAL wsrep_certify_nonPK = 1;
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result
+new file mode 100644
+index 0000000..cd52007
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result
+@@ -0,0 +1,63 @@
++SET GLOBAL wsrep_cluster_address = 'foo://';
++SHOW STATUS;
++ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++SET SESSION wsrep_sync_wait=0;
++SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
++ERROR 08S01: Unknown command
++SHOW STATUS LIKE 'wsrep_ready';
++Variable_name Value
++wsrep_ready   OFF
++SHOW STATUS LIKE 'wsrep_cluster_status';
++Variable_name Value
++wsrep_cluster_status  non-Primary
++SHOW STATUS LIKE 'wsrep_local_state';
++Variable_name Value
++wsrep_local_state     0
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++Variable_name Value
++wsrep_local_state_comment     Initialized
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 1
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1';
++SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
++ERROR 08S01: Unknown command
++SHOW STATUS LIKE 'wsrep_ready';
++Variable_name Value
++wsrep_ready   OFF
++SHOW STATUS LIKE 'wsrep_cluster_status';
++Variable_name Value
++wsrep_cluster_status  non-Primary
++SHOW STATUS LIKE 'wsrep_local_state';
++Variable_name Value
++wsrep_local_state     0
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++Variable_name Value
++wsrep_local_state_comment     Initialized
++SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++CALL mtr.add_suppression("Backend not supported: foo");
++CALL mtr.add_suppression("Failed to initialize backend using 'foo");
++CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo");
++CALL mtr.add_suppression("gcs connect failed: Socket type not supported");
++CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7");
++CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)");
++CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110");
++CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)");
++CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'gcomm://192\\.0\\.2\\.1': -110 \\(Connection timed out\\)");
++CALL mtr.add_suppression("gcs connect failed: Connection timed out");
+diff --git a/mysql-test/suite/galera/r/galera_var_desync_on.result b/mysql-test/suite/galera/r/galera_var_desync_on.result
+new file mode 100644
+index 0000000..0b5f346
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_desync_on.result
+@@ -0,0 +1,29 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
++SET GLOBAL wsrep_desync = TRUE;
++FLUSH TABLES WITH READ LOCK;
++INSERT INTO t1 VALUES (2);
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++INSERT INTO t1 VALUES (5);
++INSERT INTO t1 VALUES (6);
++INSERT INTO t1 VALUES (7);
++INSERT INTO t1 VALUES (8);
++INSERT INTO t1 VALUES (9);
++INSERT INTO t1 VALUES (10);
++SET SESSION wsrep_sync_wait = 0;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_desync = FALSE;
++UNLOCK TABLES;
++SET SESSION wsrep_sync_wait = 1;
++SELECT COUNT(*) = 10 FROM t1;
++COUNT(*) = 10
++1
++INSERT INTO t1 VALUES (11);
++SELECT COUNT(*) = 11 FROM t1;
++COUNT(*) = 11
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_fkchecks.result b/mysql-test/suite/galera/r/galera_var_fkchecks.result
+new file mode 100644
+index 0000000..342212a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_fkchecks.result
+@@ -0,0 +1,26 @@
++CREATE TABLE parent (
++id INT PRIMARY KEY,
++KEY (id)
++) ENGINE=InnoDB;
++CREATE TABLE child (
++id INT PRIMARY KEY,
++parent_id INT,
++FOREIGN KEY (parent_id) 
++REFERENCES parent(id)
++) ENGINE=InnoDB;
++INSERT INTO parent VALUES (1);
++INSERT INTO child VALUES (1,1);
++SET SESSION foreign_key_checks = 0;
++INSERT INTO child VALUES (2,2);
++SELECT COUNT(*) = 1 FROM child WHERE id = 2;
++COUNT(*) = 1
++1
++INSERT INTO child VALUES (3,3);
++ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`))
++SET SESSION foreign_key_checks = 0;
++DELETE FROM parent;
++SELECT COUNT(*) = 0 FROM parent;
++COUNT(*) = 0
++1
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result b/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result
+new file mode 100644
+index 0000000..912e45a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result
+@@ -0,0 +1,12 @@
++SET SESSION wsrep_sync_wait = 0;
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++SET GLOBAL innodb_disallow_writes=ON;
++INSERT INTO t1 VALUES (1);;
++SET GLOBAL innodb_disallow_writes=OFF;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_load_data_splitting.result b/mysql-test/suite/galera/r/galera_var_load_data_splitting.result
+new file mode 100644
+index 0000000..db145fd
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_load_data_splitting.result
+@@ -0,0 +1,9 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET GLOBAL wsrep_load_data_splitting = TRUE;
++SELECT COUNT(*) = 95000 FROM t1;
++COUNT(*) = 95000
++1
++wsrep_last_committed_diff
++1
++SET GLOBAL wsrep_load_data_splitting = 1;;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_max_ws_size.result b/mysql-test/suite/galera/r/galera_var_max_ws_size.result
+new file mode 100644
+index 0000000..6db5c24
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_max_ws_size.result
+@@ -0,0 +1,12 @@
++call mtr.add_suppression('WSREP: transaction size limit.*');
++call mtr.add_suppression('WSREP: rbr write fail.*');
++call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
++call mtr.add_suppression('WSREP: transaction size exceeded.*');
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB;
++SET GLOBAL wsrep_max_ws_size = 1024;
++INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024));
++ERROR HY000: Got error 5 during COMMIT
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result b/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result
+new file mode 100644
+index 0000000..f2a951c
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++SET GLOBAL wsrep_mysql_replication_bundle = 2;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++0
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SET GLOBAL wsrep_mysql_replication_bundle = 0;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_notify_cmd.result b/mysql-test/suite/galera/r/galera_var_notify_cmd.result
+new file mode 100644
+index 0000000..e9e4605
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_notify_cmd.result
+@@ -0,0 +1,10 @@
++SELECT COUNT(DISTINCT uuid) = 2 FROM mtr_wsrep_notify.membership;
++COUNT(DISTINCT uuid) = 2
++1
++SELECT MAX(size) = 2 FROM mtr_wsrep_notify.status;
++MAX(size) = 2
++1
++SELECT COUNT(DISTINCT idx) = 2 FROM mtr_wsrep_notify.status;
++COUNT(DISTINCT idx) = 2
++1
++DROP SCHEMA mtr_wsrep_notify;
+diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result
+new file mode 100644
+index 0000000..c8b7907
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result
+@@ -0,0 +1,8 @@
++SET GLOBAL wsrep_replicate_myisam = FALSE;
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=MyISAM;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++SET GLOBAL wsrep_replicate_myisam = 0;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result
+new file mode 100644
+index 0000000..73a0576
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result
+@@ -0,0 +1,78 @@
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=MyISAM;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (2), (3);
++INSERT INTO t1 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++SELECT COUNT(*) = 5 FROM t1;
++COUNT(*) = 5
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(100)) ENGINE=MyISAM;
++INSERT INTO t1 VALUES (1, 'abc'),(2,'abc'), (3, 'xxx');
++REPLACE INTO t1 VALUES (1, 'klm'), (2,'xyz');
++REPLACE INTO t1 SELECT 3, 'yyy' FROM DUAL;
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1 AND f2 = 'klm';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2 AND f2 = 'xyz';
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 3 AND f2 = 'yyy';
++COUNT(*) = 1
++1
++UPDATE t1 SET f2 = 'zzz' WHERE f2 = 'yyy';
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'zzz';
++COUNT(*) = 1
++1
++DELETE FROM t1 WHERE f2 = 'zzz';
++SELECT COUNT(*) = 0 FROM t1 WHERE f2 = 'zzz';
++COUNT(*) = 0
++1
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++COMMIT;
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++START TRANSACTION;
++INSERT INTO t1 VALUES (2);
++INSERT INTO t2 VALUES (2);
++ROLLBACK;
++Warnings:
++Warning       1196    Some non-transactional changed tables couldn't be rolled back
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 1 FROM t2;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++DROP TABLE t2;
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM;
++CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++COMMIT;
++DROP TABLE t1;
++DROP TABLE t2;
++SET GLOBAL wsrep_replicate_myisam = 0;
++SET GLOBAL wsrep_replicate_myisam = 0;
+diff --git a/mysql-test/suite/galera/r/galera_var_slave_threads.result b/mysql-test/suite/galera/r/galera_var_slave_threads.result
+new file mode 100644
+index 0000000..6b84f03
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_slave_threads.result
+@@ -0,0 +1,106 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
++SET GLOBAL wsrep_slave_threads = 0;
++Warnings:
++Warning       1292    Truncated incorrect wsrep_slave_threads value: '0'
++SHOW WARNINGS;
++Level Code    Message
++Warning       1292    Truncated incorrect wsrep_slave_threads value: '0'
++SELECT @@wsrep_slave_threads = 1;
++@@wsrep_slave_threads = 1
++1
++SET GLOBAL wsrep_slave_threads = 1;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_slave_threads = 64;
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++COUNT(*) = @@wsrep_slave_threads + 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_slave_threads = 1;
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++INSERT INTO t2 VALUES (DEFAULT);
++SELECT COUNT(*) = 64 FROM t2;
++COUNT(*) = 64
++1
++SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++COUNT(*) = @@wsrep_slave_threads + 1
++1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_slave_threads = 1;
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/galera_var_sync_wait.result b/mysql-test/suite/galera/r/galera_var_sync_wait.result
+new file mode 100644
+index 0000000..f6136a4
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_sync_wait.result
+@@ -0,0 +1,21 @@
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++SET GLOBAL wsrep_sync_wait = 1;
++SHOW TABLES LIKE '%t1';
++Tables_in_test (%t1)
++t1
++SELECT COUNT(*) = 0 FROM t1;
++COUNT(*) = 0
++1
++CREATE TABLE t2 (f1 INT PRIMARY KEY) Engine=InnoDB;
++SET GLOBAL wsrep_sync_wait = 4;
++INSERT INTO t2 VALUES (1);
++CREATE TABLE t3 (f1 INT PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t3 VALUES (1);
++SET GLOBAL wsrep_sync_wait = 2;
++UPDATE t3 SET f1 = 2;
++affected rows: 1
++info: Rows matched: 1  Changed: 1  Warnings: 0
++SET GLOBAL wsrep_sync_wait = 7;
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
+diff --git a/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result b/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result
+new file mode 100644
+index 0000000..8b1c4eb
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result
+@@ -0,0 +1,19 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET SESSION wsrep_on = FALSE;
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++SET GLOBAL wsrep_on = TRUE;
++INSERT INTO t1 VALUES (3);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 2;
++COUNT(*) = 0
++1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 3;
++COUNT(*) = 1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_wan.result b/mysql-test/suite/galera/r/galera_wan.result
+new file mode 100644
+index 0000000..6be32b2
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_wan.result
+@@ -0,0 +1,14 @@
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 4
++1
++CREATE TABLE t1 (f1 INTEGER);
++INSERT INTO t1 VALUES (1);
++CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside");
++SELECT VARIABLE_VALUE LIKE '%gmcast.segment = 3%' FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options';
++VARIABLE_VALUE LIKE '%gmcast.segment = 3%'
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside");
+diff --git a/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result b/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result
+new file mode 100644
+index 0000000..06fc27a
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result
+@@ -0,0 +1,33 @@
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SET GLOBAL wsrep_desync = TRUE;
++SET SESSION wsrep_on = FALSE;
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET SESSION wsrep_on = TRUE;
++SET GLOBAL wsrep_desync = FALSE;
++INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++SELECT MAX(f1) =  199999 FROM t1;
++MAX(f1) =  199999
++1
++SELECT COUNT(*) = 200000 FROM t1;
++COUNT(*) = 200000
++1
++SELECT MAX(f1) =  199999 FROM t1;
++MAX(f1) =  199999
++1
++SET GLOBAL wsrep_desync = TRUE;
++SET SESSION wsrep_on = FALSE;
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET SESSION wsrep_on = TRUE;
++SET GLOBAL wsrep_desync = FALSE;
++INSERT INTO t1 (f1) VALUES (1);
++ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
++INSERT INTO t1 (f1) VALUES (100);
++ERROR 23000: Duplicate entry '100' for key 'PRIMARY'
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result b/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result
+new file mode 100644
+index 0000000..e3f2fa4
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result
+@@ -0,0 +1,36 @@
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index';
++VARIABLE_VALUE = 0
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index';
++VARIABLE_VALUE = 0
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
+diff --git a/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result b/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
+new file mode 100644
+index 0000000..681e460
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
+@@ -0,0 +1,13 @@
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET GLOBAL wsrep_provider='none';
++INSERT INTO t1 VALUES (2);
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++SELECT COUNT(*) = 4 FROM t1;
++COUNT(*) = 4
++1
++SELECT COUNT(*) = 3 FROM t1;
++COUNT(*) = 3
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/galera_zero_length_column.result b/mysql-test/suite/galera/r/galera_zero_length_column.result
+new file mode 100644
+index 0000000..2e6119b
+--- /dev/null
++++ b/mysql-test/suite/galera/r/galera_zero_length_column.result
+@@ -0,0 +1,38 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY , f2 VARCHAR(0)) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 VARCHAR(0)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1, NULL);
++INSERT INTO t1 VALUES (2, '');
++INSERT INTO t2 VALUES (NULL);
++INSERT INTO t2 VALUES ('');
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT f2 IS NULL FROM t1 WHERE f1 = 1;
++f2 IS NULL
++1
++SELECT f2 = '' FROM t1 WHERE f1 = 2;
++f2 = ''
++1
++SELECT COUNT(*) = 2 FROM t2;
++COUNT(*) = 2
++1
++SELECT f1 IS NULL FROM t2 WHERE f1 IS NULL;
++f1 IS NULL
++1
++SELECT f1 = '' FROM t2 WHERE f1 IS NOT NULL;
++f1 = ''
++1
++UPDATE t1 SET f2 = '' WHERE f1 = 1;
++UPDATE t1 SET f2 = NULL WHERE f1 = 2;
++UPDATE t2 SET f1 = '' WHERE f1 IS NULL;
++SELECT f2 = '' FROM t1 WHERE f1 = 1;
++f2 = ''
++1
++SELECT f2 IS NULL FROM t1 WHERE f1 = 2;
++f2 IS NULL
++1
++SELECT COUNT(*) = 2 FROM t2 WHERE f1 = '';
++COUNT(*) = 2
++1
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/r/lp1276424.result b/mysql-test/suite/galera/r/lp1276424.result
+new file mode 100644
+index 0000000..5f09ec9
+--- /dev/null
++++ b/mysql-test/suite/galera/r/lp1276424.result
+@@ -0,0 +1,11 @@
++CREATE TABLE t1 (f1 INT DEFAULT NULL, UNIQUE KEY i1 (f1)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL);
++INSERT INTO t1 VALUES (NULL);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++SELECT f1 IS NULL FROM t1;
++f1 IS NULL
++1
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/r/lp1347768.result b/mysql-test/suite/galera/r/lp1347768.result
+new file mode 100644
+index 0000000..c085059
+--- /dev/null
++++ b/mysql-test/suite/galera/r/lp1347768.result
+@@ -0,0 +1,17 @@
++CREATE TABLE `r8kmb_redirect_links` (
++`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
++`old_url` varchar(255) DEFAULT NULL,
++`new_url` varchar(255) NOT NULL,
++`referer` varchar(150) NOT NULL,
++`comment` varchar(255) NOT NULL,
++`published` tinyint(4) NOT NULL,
++`created_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
++`modified_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
++PRIMARY KEY (`id`),
++UNIQUE KEY `idx_link_old` (`old_url`),
++KEY `idx_link_modifed` (`modified_date`)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++INSERT INTO r8kmb_redirect_links VALUES (550,'http://mysite.com/images/download/ßуñûічýøù_ôþóþòір_þфõÑ.doc','','','',0,'2013-07-15 14:29:42','0000-00-00 00:00:00');
++Warnings:
++Warning       1265    Data truncated for column 'old_url' at row 1
++DROP TABLE r8kmb_redirect_links;
+diff --git a/mysql-test/suite/galera/r/lp959512.result b/mysql-test/suite/galera/r/lp959512.result
+new file mode 100644
+index 0000000..55adfa3
+--- /dev/null
++++ b/mysql-test/suite/galera/r/lp959512.result
+@@ -0,0 +1,24 @@
++DROP TABLE IF EXISTS variable;
++Warnings:
++Note  1051    Unknown table 'test.variable'
++DROP TABLE IF EXISTS foo;
++Warnings:
++Note  1051    Unknown table 'test.foo'
++CREATE TABLE variable (
++name varchar(128) NOT NULL DEFAULT '' COMMENT 'The name of the variable.',
++value longblob NOT NULL COMMENT 'The value of the variable.',
++PRIMARY KEY (name)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Named variable/value pairs created by Drupal core or any...';
++CREATE TABLE foo (a int);
++INSERT INTO variable (name, value) VALUES ('menu_expanded', 'a:0:{}');
++START TRANSACTION;
++SELECT 1 AS expression FROM variable variable
++WHERE ( (name = 'menu_expanded') ) FOR UPDATE;
++expression
++1
++UPDATE variable SET value='a:0:{}' WHERE ( (name = 'menu_expanded') );
++COMMIT;
++INSERT INTO foo VALUES (1);
++UPDATE foo SET a = 2 WHERE a = 1;
++DROP TABLE foo;
++DROP TABLE variable;
+diff --git a/mysql-test/suite/galera/t/disabled.def b/mysql-test/suite/galera/t/disabled.def
+new file mode 100644
+index 0000000..a1495c6
+--- /dev/null
++++ b/mysql-test/suite/galera/t/disabled.def
+@@ -0,0 +1,4 @@
++galera_wsrep_provider_unset_set : lp1379204 'Unsupported protocol downgrade: incremental data collection disabled. Expect abort.'
++galera_kill_nochanges : mysql-wsrep#24 Galera server does not restart properly if killed
++galera_bf_abort_for_update : mysql-wsrep#26 SELECT FOR UPDATE sometimes allowed to proceed in the face of a concurrent update
++galera_toi_ddl_fk_insert : qa#39 galera_toi_ddl_fk_insert fails sporadically
+diff --git a/mysql-test/suite/galera/t/galera_account_management.test b/mysql-test/suite/galera/t/galera_account_management.test
+new file mode 100644
+index 0000000..357319a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_account_management.test
+@@ -0,0 +1,101 @@
++#
++# Test the account management statements - GRANT, REVOKE, etc.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# CREATE USER
++#
++--connection node_1
++CREATE USER user1, user2 IDENTIFIED BY 'password';
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM mysql.user WHERE user IN ('user1', 'user2');
++
++#
++# ALTER USER
++#
++
++# LP bug 1376269
++#
++#--connection node_1
++#ALTER USER user1 PASSWORD EXPIRE;
++#SELECT password_expired = 'Y' FROM mysql.user WHERE user = 'user1';
++#
++#--connection node_2
++#SELECT password_expired = 'Y' FROM mysql.user WHERE user = 'user1';
++
++#
++# RENAME USER
++#
++
++--connection node_1
++RENAME USER user2 TO user3;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM mysql.user WHERE user = 'user2';
++SELECT COUNT(*) = 1 FROM mysql.user WHERE user = 'user3';
++
++#
++# SET PASSWORD
++#
++
++--connection node_1
++SET PASSWORD FOR user3 = PASSWORD('foo');
++
++--connection node_1
++SELECT password != '' FROM mysql.user WHERE user = 'user3';
++
++#
++# DROP USER
++#
++--connection node_1
++DROP USER user1, user3;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM mysql.user WHERE user IN ('user1', 'user2');
++
++#
++# GRANT
++#
++
++--connection node_1
++GRANT ALL ON *.* TO user4 IDENTIFIED BY 'password';
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM mysql.user WHERE user = 'user4';
++SELECT Select_priv = 'Y' FROM mysql.user WHERE user = 'user4';
++
++#
++# GRANT PROXY ON
++#
++--connection node_1
++CREATE USER user5;
++GRANT PROXY ON user4 TO user5;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM mysql.proxies_priv WHERE user = 'user5';
++
++#
++# REVOKE
++#
++
++--connection node_1
++REVOKE ALL PRIVILEGES ON *.* FROM user4;
++
++--connection node_2
++SELECT Select_priv = 'N' FROM mysql.user WHERE user = 'user4';
++
++#
++# REVOKE PROXY
++#
++
++--connection node_1
++REVOKE PROXY ON user4 FROM user5;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM mysql.proxies_priv WHERE user = 'user5';
++
++DROP USER user4, user5;
+diff --git a/mysql-test/suite/galera/t/galera_alter_engine_innodb.test b/mysql-test/suite/galera/t/galera_alter_engine_innodb.test
+new file mode 100644
+index 0000000..bc914a3
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_alter_engine_innodb.test
+@@ -0,0 +1,17 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test ALTER ENGINE from InnoDB to InnoDB
++#
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++ALTER TABLE t1 ENGINE=InnoDB;
++
++--connection node_2
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_alter_engine_myisam.test b/mysql-test/suite/galera/t/galera_alter_engine_myisam.test
+new file mode 100644
+index 0000000..6d41d27
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_alter_engine_myisam.test
+@@ -0,0 +1,25 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test ALTER ENGINE from MyISAM to InnoDB under wsrep_replicate_myisam
++#
++
++--let $wsrep_replicate_myisam_orig = `SELECT @@wsrep_replicate_myisam`
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++INSERT INTO t1 VALUES (1);
++
++ALTER TABLE t1 ENGINE=InnoDB;
++
++--connection node_2
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_alter_table_force.test b/mysql-test/suite/galera/t/galera_alter_table_force.test
+new file mode 100644
+index 0000000..1fcc9d4
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_alter_table_force.test
+@@ -0,0 +1,17 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test ALTER TABLE FORCE, a 5.6.3 feature that simply rebuilds the table
++#
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++ALTER TABLE t1 FORCE;
++
++--connection node_2
++SELECT ENGINE = 'InnoDB' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_as_master.cnf b/mysql-test/suite/galera/t/galera_as_master.cnf
+new file mode 100644
+index 0000000..52fd309
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master.cnf
+@@ -0,0 +1 @@
++!include ../galera_2nodes_as_master.cnf
+diff --git a/mysql-test/suite/galera/t/galera_as_master.test b/mysql-test/suite/galera/t/galera_as_master.test
+new file mode 100644
+index 0000000..3367a20
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master.test
+@@ -0,0 +1,39 @@
++#
++# Test Galera as a master to a MySQL slave
++#
++# The galera/galera_2node_master.cnf describes the setup of the nodes
++#
++
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++--source include/galera_cluster.inc
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++--disable_query_log
++--eval CHANGE MASTER TO  MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++
++--connection node_2
++INSERT INTO t1 VALUES(2);
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 2 FROM t1;
++--source include/wait_condition.inc
++
++--connection node_1
++DROP TABLE t1;
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid.cnf b/mysql-test/suite/galera/t/galera_as_master_gtid.cnf
+new file mode 100644
+index 0000000..1951755
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master_gtid.cnf
+@@ -0,0 +1,8 @@
++!include ../galera_2nodes_as_master.cnf
++
++[mysqld]
++gtid-mode=ON
++log-bin=mysqld-bin
++log-slave-updates
++enforce-gtid-consistency
++binlog-format=ROW
+diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid.test b/mysql-test/suite/galera/t/galera_as_master_gtid.test
+new file mode 100644
+index 0000000..9db104b
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master_gtid.test
+@@ -0,0 +1,70 @@
++#
++# Test Galera as a master to a MySQL slave with GTID
++#
++# The galera/galera_2node_master.cnf describes the setup of the nodes
++#
++# We check that all transactions originating from within Galera use a UUID that is 
++# different from the server_uuid of either node
++#
++#
++
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++--source include/galera_cluster.inc
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++--disable_query_log
++--eval CHANGE MASTER TO  MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++
++--let $effective_uuid = `SELECT LEFT(@@global.gtid_executed, 36)`
++--disable_query_log
++--eval SELECT '$effective_uuid' != @@global.server_uuid AS uuids_do_not_match;
++--enable_query_log
++
++--replace_result $effective_uuid <effective_uuid>
++--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
++SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 120;
++
++--connection node_2
++INSERT INTO t1 VALUES(2);
++
++--disable_query_log
++--eval SELECT '$effective_uuid' != @@global.server_uuid AS uuids_do_not_match;
++--eval SELECT '$effective_uuid' = LEFT(@@global.gtid_executed, 36) AS uuids_match;
++--enable_query_log
++
++--replace_result $effective_uuid <effective_uuid>
++--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
++SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 120;
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 2 FROM t1;
++--source include/wait_condition.inc
++
++--disable_query_log
++--eval SELECT '$effective_uuid' != @@global.server_uuid AS uuids_do_not_match;
++--eval SELECT '$effective_uuid' = LEFT(@@global.gtid_executed, 36) AS uuids_match;
++--enable_query_log
++
++--replace_result $effective_uuid <effective_uuid>
++--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
++SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
++
++--connection node_1
++DROP TABLE t1;
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf
+new file mode 100644
+index 0000000..1951755
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf
+@@ -0,0 +1,8 @@
++!include ../galera_2nodes_as_master.cnf
++
++[mysqld]
++gtid-mode=ON
++log-bin=mysqld-bin
++log-slave-updates
++enforce-gtid-consistency
++binlog-format=ROW
+diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test
+new file mode 100644
+index 0000000..23606d7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test
+@@ -0,0 +1,54 @@
++#
++# Test that a MySQL slave can use CHANGE MASTER MASTER_AUTO_POSITION to begin replicating
++# from another Galera node
++#
++# The galera/galera_2node_master.cnf describes the setup of the nodes
++#
++#
++
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++--source include/galera_cluster.inc
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++--disable_query_log
++--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++
++--connection node_2
++INSERT INTO t1 VALUES(2);
++
++--connection node_3
++STOP SLAVE;
++--disable_query_log
++--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_2, MASTER_AUTO_POSITION=1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++INSERT INTO t1 VALUES(3);
++
++--connection node_2
++INSERT INTO t1 VALUES(4);
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 4 FROM t1;
++--source include/wait_condition.inc
++
++--connection node_1
++DROP TABLE t1;
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/t/galera_as_slave.cnf b/mysql-test/suite/galera/t/galera_as_slave.cnf
+new file mode 100644
+index 0000000..9449ec9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_slave.cnf
+@@ -0,0 +1 @@
++!include ../galera_2nodes_as_slave.cnf
+diff --git a/mysql-test/suite/galera/t/galera_as_slave.test b/mysql-test/suite/galera/t/galera_as_slave.test
+new file mode 100644
+index 0000000..0f899fd
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_slave.test
+@@ -0,0 +1,48 @@
++#
++# Test Galera as a slave to a MySQL master
++#
++# The galera/galera_2node_slave.cnf describes the setup of the nodes
++#
++
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++
++# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
++--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
++--source include/galera_cluster.inc
++
++--connection node_2
++--disable_query_log
++--eval CHANGE MASTER TO  MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++
++--connection node_2
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 1 FROM t1;
++--source include/wait_condition.inc
++
++INSERT INTO t1 VALUES (2);
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++SELECT COUNT(*) = 2 FROM t1;
++INSERT INTO t1 VALUES (3);
++
++--connection node_2
++SELECT COUNT(*) = 3 FROM t1;
++
++--connection node_1
++DROP TABLE t1;
++
++--connection node_2
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid.cnf b/mysql-test/suite/galera/t/galera_as_slave_gtid.cnf
+new file mode 100644
+index 0000000..92f6a16
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_slave_gtid.cnf
+@@ -0,0 +1,8 @@
++!include ../galera_2nodes_as_slave.cnf
++
++[mysqld]
++gtid-mode=ON
++log-bin=mysqld-bin
++log-slave-updates
++enforce-gtid-consistency
++binlog-format=ROW
+diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid.test b/mysql-test/suite/galera/t/galera_as_slave_gtid.test
+new file mode 100644
+index 0000000..02fe5f7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_as_slave_gtid.test
+@@ -0,0 +1,68 @@
++#
++# Test Galera as a slave to a MySQL master using GTIDs
++#
++# suite/galera/galera_2nodes_as_slave.cnf describes the setup of the nodes
++# suite/galera/t/galera_as_slave_gtid.cnf has the GTID options
++#
++# In addition to performing DDL and DML, we check that the gtid of the master is preserved inside the cluster
++#
++
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++
++# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
++--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
++--source include/galera_cluster.inc
++
++--connection node_2
++--disable_query_log
++--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES(1);
++
++SELECT LENGTH(@@global.gtid_executed) > 1;
++--let $gtid_executed_node1 = `SELECT @@global.gtid_executed;`
++
++--connection node_2
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 1 FROM t1;
++--source include/wait_condition.inc
++
++--disable_query_log
++--eval SELECT '$gtid_executed_node1' = @@global.gtid_executed AS gtid_executed_equal;
++--enable_query_log
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++SELECT COUNT(*) = 1 FROM t1;
++
++--disable_query_log
++--eval SELECT '$gtid_executed_node1' = @@global.gtid_executed AS gtid_executed_equal;
++--enable_query_log
++
++--connection node_1
++DROP TABLE t1;
++
++#
++# Unfortunately without the sleep below the following statement fails with "query returned no rows", which
++# is difficult to understand given that it is an aggregate query. A "query execution was interrupted"
++# warning is also reported by MTR, which is also weird.
++#
++
++--sleep 1
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--connection node_2
++--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++STOP SLAVE;
++RESET SLAVE ALL;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort.test b/mysql-test/suite/galera/t/galera_bf_abort.test
+new file mode 100644
+index 0000000..69825ea
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort.test
+@@ -0,0 +1,29 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test a local transaction being aborted by a slave one
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++INSERT INTO t1 VALUES (2);
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort_for_update.test b/mysql-test/suite/galera/t/galera_bf_abort_for_update.test
+new file mode 100644
+index 0000000..24c2977
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort_for_update.test
+@@ -0,0 +1,29 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test a local transaction being aborted by a slave one while it is running a SELECT FOR UPDATE
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++SELECT * FROM t1 FOR UPDATE;
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ftwrl.test b/mysql-test/suite/galera/t/galera_bf_abort_ftwrl.test
+new file mode 100644
+index 0000000..44398e7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort_ftwrl.test
+@@ -0,0 +1,30 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# A local transaction running FLUSH TABLES WITH READ LOCK will not be aborted by a slave transaction
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++--send FLUSH TABLES WITH READ LOCK;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--reap
++
++UNLOCK TABLES;
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++# No aborts should be registered on the counter
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 0 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test
+new file mode 100644
+index 0000000..72fc1c5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test
+@@ -0,0 +1,36 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test a local transaction being aborted by a slave one while it is running a GET_LOCK()
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++SELECT GET_LOCK("foo", 1000);
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++INSERT INTO t1 VALUES (1);
++--send SELECT GET_LOCK("foo", 1000);
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++--reap
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++# Check that wsrep_local_bf_aborts has been incremented by exactly 1
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort_lock_table.test b/mysql-test/suite/galera/t/galera_bf_abort_lock_table.test
+new file mode 100644
+index 0000000..7884271
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort_lock_table.test
+@@ -0,0 +1,33 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test that a local LOCK TABLE will be broken by an incoming remote transaction against that table
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++LOCK TABLE t1 WRITE;
++
++# Issue a concurrent INSERT against the lock table that will block
++--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
++--send INSERT INTO t1 VALUES (1);
++
++--connection node_1
++INSERT INTO t1 VALUES (2);
++
++# The concurent insert is allowed to complete because the LOCK TABLE is now broken
++--connection node_2a
++--error 0
++--reap
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_bf_abort_sleep.test b/mysql-test/suite/galera/t/galera_bf_abort_sleep.test
+new file mode 100644
+index 0000000..8d135dc
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_bf_abort_sleep.test
+@@ -0,0 +1,30 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test a local transaction being aborted by a slave one while it is running a SLEEP()
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++INSERT INTO t1 VALUES (1);
++--send SELECT SLEEP(1000);
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++--reap
++
++--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'`
++
++# Check that wsrep_local_bf_aborts has been incremented by exactly 1
++--disable_query_log
++--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_binlog_cache_size.test b/mysql-test/suite/galera/t/galera_binlog_cache_size.test
+new file mode 100644
+index 0000000..6ce9072
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_cache_size.test
+@@ -0,0 +1,35 @@
++#
++# Test that Galera, like the stock MySQL, returns an error on transactions
++# larger than max_binlog_cache_size
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 VARCHAR(767)) ENGINE=InnoDB;
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++--let $max_binlog_cache_size_orig = `SELECT @@max_binlog_cache_size`
++--let $binlog_cache_size_orig = `SELECT @@binlog_cache_size`
++
++SET GLOBAL binlog_cache_size=4096;
++SET GLOBAL max_binlog_cache_size=4096;
++
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++--connection node_1a
++SET AUTOCOMMIT=ON;
++START TRANSACTION;
++INSERT INTO t1 SELECT REPEAT('a', 767) FROM ten;
++--error ER_TRANS_CACHE_FULL
++INSERT INTO t1 SELECT REPEAT('a', 767) FROM ten;
++
++--disable_query_log
++--eval SET GLOBAL max_binlog_cache_size = $max_binlog_cache_size_orig
++--eval SET GLOBAL binlog_cache_size = $binlog_cache_size_orig
++--enable_query_log
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_binlog_checksum-master.opt b/mysql-test/suite/galera/t/galera_binlog_checksum-master.opt
+new file mode 100644
+index 0000000..c8e53f0
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_checksum-master.opt
+@@ -0,0 +1 @@
++--binlog-checksum=CRC32 --master-verify-checksum=1 --slave-sql-verify-checksum=1
+diff --git a/mysql-test/suite/galera/t/galera_binlog_checksum.test b/mysql-test/suite/galera/t/galera_binlog_checksum.test
+new file mode 100644
+index 0000000..4866930
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_checksum.test
+@@ -0,0 +1,22 @@
++#
++# Test that Galera works with binary log checksums.
++# The galera_binlog_checksum-master.opt file is used to enable checksums.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_binlog_event_max_size_max-master.opt b/mysql-test/suite/galera/t/galera_binlog_event_max_size_max-master.opt
+new file mode 100644
+index 0000000..a36d213
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_event_max_size_max-master.opt
+@@ -0,0 +1 @@
++--binlog-row-event-max-size=4294967295
+diff --git a/mysql-test/suite/galera/t/galera_binlog_event_max_size_max.test b/mysql-test/suite/galera/t/galera_binlog_event_max_size_max.test
+new file mode 100644
+index 0000000..600432c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_event_max_size_max.test
+@@ -0,0 +1,20 @@
++#
++# Test that replication works event with the maximum value of binlog-row-event-max-size - 4294967295 (on 32-bit platforms)
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 VARCHAR(1000));
++
++# Insert 10K records, 1K bytes each
++INSERT INTO t1 SELECT REPEAT('x', 1000) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--connection node_2
++SELECT COUNT(*) = 10000 FROM t1;
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_binlog_event_max_size_min-master.opt b/mysql-test/suite/galera/t/galera_binlog_event_max_size_min-master.opt
+new file mode 100644
+index 0000000..2217475
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_event_max_size_min-master.opt
+@@ -0,0 +1 @@
++--binlog-row-event-max-size=256
+diff --git a/mysql-test/suite/galera/t/galera_binlog_event_max_size_min.test b/mysql-test/suite/galera/t/galera_binlog_event_max_size_min.test
+new file mode 100644
+index 0000000..00b5533
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_event_max_size_min.test
+@@ -0,0 +1,15 @@
++#
++# Test that replication works event with the minimum value of binlog-row-event-max-size - 256
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 VARCHAR(1000));
++INSERT INTO t1 VALUES (REPEAT('x', 1000));
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = REPEAT('x', 1000);
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_binlog_row_image.test b/mysql-test/suite/galera/t/galera_binlog_row_image.test
+new file mode 100644
+index 0000000..70262ec
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_row_image.test
+@@ -0,0 +1,100 @@
++#
++# Test the operation on the different values of the binlog_row_image option
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# binlog_row_image = minimal 
++#
++
++--connection node_1
++SET SESSION binlog_row_image=minimal;
++
++# Create a table with a PK, with a unique key and with no key
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER NOT NULL UNIQUE) ENGINE=InnoDB;
++CREATE TABLE t3 (f1 VARCHAR(1)) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t3 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 1;
++SELECT COUNT(*) = 1 FROM t3 WHERE f1 = 1;
++
++--connection node_1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++UPDATE t2 SET f1 = 2 WHERE f1 = 1;
++UPDATE t3 SET f1 = 2 WHERE f1 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 2;
++SELECT COUNT(*) = 1 FROM t3 WHERE f1 = 2;
++
++--connection node_1
++DELETE FROM t1;
++DELETE FROM t2;
++DELETE FROM t3;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++SELECT COUNT(*) = 0 FROM t3;
++
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++
++#
++# binlog_row_image = noblob
++#
++
++# A table with only a blob, and a table with a PK and a blob
++
++--connection node_1
++SET SESSION binlog_row_image=noblob;
++
++CREATE TABLE t1 (f1 BLOB, f2 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES ('abc', 1);
++INSERT INTO t2 VALUES ('abc');
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'abc';
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 'abc';
++
++--connection node_1
++UPDATE t1 SET f1 = 'xyz';
++UPDATE t2 SET f1 = 'xyz';
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'xyz';
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 'xyz';
++
++--connection node_1
++UPDATE t1 SET f2 = 2 WHERE f2 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 2;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'xyz';
++
++--connection node_1
++DELETE FROM t1;
++DELETE FROM t2;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++
++DROP TABLE t1;
++DROP TABLE t2;
++
++
++
++
+diff --git a/mysql-test/suite/galera/t/galera_binlog_rows_query_log_events.test b/mysql-test/suite/galera/t/galera_binlog_rows_query_log_events.test
+new file mode 100644
+index 0000000..95bc85c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_binlog_rows_query_log_events.test
+@@ -0,0 +1,28 @@
++#
++# Test that Galera continues to run even with binlog-rows-query-log-events=TRUE
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $binlog_rows_query_log_events_orig = `SELECT @@binlog_rows_query_log_events`
++
++SET GLOBAL binlog_rows_query_log_events=TRUE;
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++
++--connection node_1
++--eval SET GLOBAL binlog_rows_query_log_events = $binlog_rows_query_log_events_orig
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_create_function.test b/mysql-test/suite/galera/t/galera_create_function.test
+new file mode 100644
+index 0000000..fd4903a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_create_function.test
+@@ -0,0 +1,57 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test CREATE FUNCTION
++#
++
++--connection node_1
++CREATE USER 'user1';
++
++CREATE
++DEFINER = 'user1'
++FUNCTION f1 (param INTEGER)
++RETURNS VARCHAR(200)
++COMMENT 'f1_comment'
++LANGUAGE SQL
++NOT DETERMINISTIC
++MODIFIES SQL DATA
++SQL SECURITY DEFINER
++RETURN 'abc';
++GRANT EXECUTE ON FUNCTION f1 TO user1;
++
++CREATE
++DEFINER = CURRENT_USER
++FUNCTION f2 (param VARCHAR(100))
++RETURNS INTEGER
++DETERMINISTIC
++NO SQL
++SQL SECURITY INVOKER
++RETURN 123;
++
++--connection node_1
++SHOW CREATE FUNCTION f1;
++
++--connection node_2
++SHOW CREATE FUNCTION f1;
++
++--connection node_1
++SHOW CREATE FUNCTION f2;
++
++--connection node_2
++SHOW CREATE FUNCTION f2;
++
++SELECT f1(1) = 'abc';
++SELECT f2('abc') = 123;
++
++--connection node_1
++DROP FUNCTION f1;
++DROP FUNCTION f2;
++
++DROP USER 'user1';
++
++
++
++
++
++
+diff --git a/mysql-test/suite/galera/t/galera_create_procedure.test b/mysql-test/suite/galera/t/galera_create_procedure.test
+new file mode 100644
+index 0000000..30bc85f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_create_procedure.test
+@@ -0,0 +1,52 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test CREATE PROCEDURE
++#
++
++--connection node_1
++CREATE USER 'user1';
++CREATE TABLE t1 (f1 INTEGER);
++
++CREATE
++DEFINER = 'user1'
++PROCEDURE p1 (IN param1 INTEGER, OUT param2 INTEGER, INOUT param3 INTEGER)
++COMMENT 'p1_comment'
++LANGUAGE SQL
++NOT DETERMINISTIC
++MODIFIES SQL DATA
++SQL SECURITY DEFINER
++INSERT INTO t1 VALUES (1);
++GRANT EXECUTE ON PROCEDURE p1 TO user1;
++
++CREATE
++DEFINER = CURRENT_USER
++PROCEDURE p2 (param VARCHAR(100))
++DETERMINISTIC
++NO SQL
++SQL SECURITY INVOKER BEGIN END ;
++
++--connection node_1
++SHOW CREATE PROCEDURE p1;
++
++--connection node_2
++# Perform causal wait
++SELECT 1 FROM DUAL;
++SHOW CREATE PROCEDURE p1;
++
++--connection node_1
++SHOW CREATE PROCEDURE p2;
++
++--connection node_2
++SHOW CREATE PROCEDURE p2;
++
++CALL p1(@a, @b, @c);
++CALL p2('abc');
++
++--connection node_1
++DROP PROCEDURE p1;
++DROP PROCEDURE p2;
++
++DROP USER 'user1';
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_create_table_like.test b/mysql-test/suite/galera/t/galera_create_table_like.test
+new file mode 100644
+index 0000000..0e0e8b0
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_create_table_like.test
+@@ -0,0 +1,50 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test the various forms of CREATE TABLE LIKE ... , since Galera has special handling
++# for them, especially when one of the tables is a temporary one.
++#
++
++CREATE SCHEMA schema1;
++CREATE SCHEMA schema2;
++
++USE schema1;
++CREATE TABLE real_table (f1 INTEGER) ENGINE=InnoDB;
++CREATE TEMPORARY TABLE temp_table (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE myisam_table (f1 INTEGER) ENGINE=MyISAM;
++
++USE schema2;
++CREATE TABLE real_table1 LIKE schema1.real_table;
++CREATE TABLE real_table2 LIKE schema1.temp_table;
++CREATE TABLE real_table3 LIKE schema1.myisam_table;
++
++CREATE TEMPORARY TABLE temp_table1 LIKE schema1.real_table;
++CREATE TEMPORARY TABLE temp_table2 LIKE schema1.temp_table;
++CREATE TEMPORARY TABLE temp_table3 LIKE schema1.myisam_table;
++
++--connection node_2
++# Only the non-temporary tables are replicated, regardless of the type of table they are based on
++
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table' AND TABLE_SCHEMA = 'schema1';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'myisam_table' AND TABLE_SCHEMA = 'schema1';
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table' AND TABLE_SCHEMA = 'schema1';
++
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table1' AND TABLE_SCHEMA = 'schema2';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table2' AND TABLE_SCHEMA = 'schema2';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'real_table3' AND TABLE_SCHEMA = 'schema2';
++
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table1' AND TABLE_SCHEMA = 'schema2';
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table2' AND TABLE_SCHEMA = 'schema2';
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_table3' AND TABLE_SCHEMA = 'schema2';
++
++--connection node_1
++DROP TABLE schema1.real_table;
++DROP TABLE schema1.myisam_table;
++
++DROP TABLE schema2.real_table1;
++DROP TABLE schema2.real_table2;
++DROP TABLE schema2.real_table3;
++
++DROP SCHEMA schema1;
++DROP SCHEMA schema2;
+diff --git a/mysql-test/suite/galera/t/galera_create_trigger.test b/mysql-test/suite/galera/t/galera_create_trigger.test
+new file mode 100644
+index 0000000..74dc616
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_create_trigger.test
+@@ -0,0 +1,48 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test CREATE TRIGGER, especially with different DEFINER
++#
++
++CREATE TABLE definer_root (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_current_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++CREATE TABLE definer_default (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
++
++CREATE USER 'user1';
++CREATE DEFINER=root@localhost TRIGGER definer_root BEFORE INSERT ON definer_root FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE DEFINER=user1 TRIGGER definer_user BEFORE INSERT ON definer_user FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE DEFINER=current_user TRIGGER definer_current_user BEFORE INSERT ON definer_current_user FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++CREATE TRIGGER definer_default BEFORE INSERT ON definer_default FOR EACH ROW SET NEW.trigger_user = CURRENT_USER();
++
++--connection node_2
++INSERT INTO definer_root (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_root';
++SELECT trigger_user = 'root@localhost' FROM definer_root;
++
++INSERT INTO definer_user (f1) VALUES (1);
++SELECT DEFINER = 'user1@%' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_user';
++SELECT trigger_user = 'user1@%' FROM definer_user;
++
++INSERT INTO definer_current_user (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_current_user';
++SELECT trigger_user = 'root@localhost' FROM definer_current_user;
++
++INSERT INTO definer_default (f1) VALUES (1);
++SELECT DEFINER = 'root@localhost' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'definer_default';
++SELECT trigger_user = 'root@localhost' FROM definer_default;
++
++--connection node_1
++DROP TABLE definer_current_user;
++DROP TABLE definer_user;
++DROP TABLE definer_root;
++DROP TABLE definer_default;
++
++DROP USER 'user1';
++
++
++
++
++
++
+diff --git a/mysql-test/suite/galera/t/galera_defaults.test b/mysql-test/suite/galera/t/galera_defaults.test
+new file mode 100644
+index 0000000..25d85b7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_defaults.test
+@@ -0,0 +1,63 @@
++#
++# The purpose of this test is to preserve the current state of the following:
++# * SHOW VARIABLES LIKE 'wsrep%'
++# * wsrep_provider_options
++# * The names of the Galera status variables
++#
++# This way, if there is any change, inadvertent or not, the test will fail and the
++# developer and QA will be alerted.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++# Global Variables
++
++SELECT COUNT(*) = 40 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
++
++SELECT VARIABLE_NAME, VARIABLE_VALUE
++FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME NOT IN (
++      'WSREP_PROVIDER_OPTIONS',
++      'WSREP_SST_RECEIVE_ADDRESS',
++      'WSREP_NODE_ADDRESS',
++      'WSREP_NODE_NAME',
++      'WSREP_PROVIDER',
++      'WSREP_DATA_HOME_DIR',
++      'WSREP_NODE_INCOMING_ADDRESS',
++      'WSREP_START_POSITION'
++)
++ORDER BY VARIABLE_NAME;
++
++# wsrep_provider_options
++#
++# We replace the ones that vary from run to run with placeholders
++
++--let _WSREP_PROVIDER_OPTIONS = `SELECT @@wsrep_provider_options`
++--perl
++      use strict;
++      my $wsrep_provider_options = $ENV{'_WSREP_PROVIDER_OPTIONS'};
++      $wsrep_provider_options =~ s/base_dir = .*?;/<BASE_DIR>;/sgio;
++      $wsrep_provider_options =~ s/base_host = .*?;/<BASE_HOST>;/sgio;
++      $wsrep_provider_options =~ s/base_port = .*?;/<BASE_PORT>;/sgio;
++      $wsrep_provider_options =~ s/gcache\.dir = .*?;/<GCACHE_DIR>;/sgio;
++      $wsrep_provider_options =~ s/gcache\.name = .*?;/<GCACHE_NAME>;/sgio;
++      $wsrep_provider_options =~ s/gmcast\.listen_addr = .*?;/<GMCAST_LISTEN_ADDR>;/sgio;
++      $wsrep_provider_options =~ s/ist\.recv_addr = .*?;/<IST_RECV_ADDR>;/sgio;
++      $wsrep_provider_options =~ s/evs\.evict = .*?;/<EVS_EVICT>;/sgio;
++      $wsrep_provider_options =~ s/signal = .*?;\s*//sgio;
++      $wsrep_provider_options =~ s/dbug = .*?;\s*//sgio;
++      print $wsrep_provider_options."\n";
++EOF
++
++# Global Status
++
++SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_STATUS
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME != 'wsrep_debug_sync_waiters';
++
++SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_STATUS
++WHERE VARIABLE_NAME LIKE 'wsrep_%'
++AND VARIABLE_NAME != 'wsrep_debug_sync_waiters'
++ORDER BY VARIABLE_NAME;
+diff --git a/mysql-test/suite/galera/t/galera_delete_limit.test b/mysql-test/suite/galera/t/galera_delete_limit.test
+new file mode 100644
+index 0000000..4cbadbd
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_delete_limit.test
+@@ -0,0 +1,52 @@
++#
++# DELETE LIMIT should not cause any issues with row-based Galera replication
++# regardless of the order in which the rows were deleted
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# With a PK
++#
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 SELECT f1 FROM ten ORDER BY RAND();
++
++--connection node_2
++DELETE FROM t1 ORDER BY RAND() LIMIT 5;
++--let $sum_remaining = `SELECT SUM(f1) FROM t1`
++--let $max_remaining = `SELECT MAX(f1) FROM t1`
++
++--connection node_1
++--disable_query_log
++--eval SELECT (SELECT SUM(f1) FROM t1) = $sum_remaining AS sum_matches;
++--eval SELECT f1 = $max_remaining AS max_matches FROM t1 WHERE f1 = $max_remaining;
++--enable_query_log
++
++DROP TABLE t1;
++
++#
++# Without a PK
++#
++
++CREATE TABLE t2 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t2 SELECT f1 FROM ten ORDER BY RAND();
++
++--connection node_2
++DELETE FROM t2 ORDER BY RAND() LIMIT 5;
++--let $sum_remaining = `SELECT SUM(f1) FROM t2`
++--let $max_remaining = `SELECT MAX(f1) FROM t2`
++
++--connection node_1
++--disable_query_log
++--eval SELECT (SELECT SUM(f1) FROM t2) = $sum_remaining AS sum_matches;
++--eval SELECT f1 = $max_remaining AS max_matches FROM t2 WHERE f1 = $max_remaining;
++--enable_query_log
++
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_enum.test b/mysql-test/suite/galera/t/galera_enum.test
+new file mode 100644
+index 0000000..ff53324
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_enum.test
+@@ -0,0 +1,62 @@
++#
++# Test the ENUM column type, as it is frequently an unwanted child
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# ENUM as key
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 ENUM('', 'one', 'two'), KEY (f1)) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES ('');
++INSERT INTO t1 VALUES ('one'), ('two');
++INSERT INTO t1 VALUES (0), (1), (2);
++
++--connection node_2
++SELECT COUNT(*) = 6 FROM t1;
++SELECT COUNT(*) = 2 FROM t1 where f1 = '';
++SELECT COUNT(*) = 2 FROM t1 where f1 = 'one';
++
++DROP TABLE t1;
++
++#
++# ENUM as PK
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 ENUM('', 'one', 'two', 'three', 'four') PRIMARY KEY) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (''), ('one'), ('two');
++
++--connection node_2
++SELECT COUNT(*) = 3 FROM t1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = '';
++
++# Conflict
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'three' where f1 = '';
++
++--connection node_2
++SET AUTOCOMMIt=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'four' where f1 = '';
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++--connection node_1
++
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 'three';
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_events.test b/mysql-test/suite/galera/t/galera_events.test
+new file mode 100644
+index 0000000..ae9940f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_events.test
+@@ -0,0 +1,53 @@
++#
++# Test that the replication of MySQL events conforms to the behavior of stock MySQL replication as described here
++# http://dev.mysql.com/doc/refman/5.6/en/replication-features-invoked.html
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $event_scheduler_orig = `SELECT @@event_scheduler;`
++
++#
++# Events arrive on slave as SLAVESIDE_DISABLED
++#
++
++--connection node_1
++CREATE EVENT event1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO SELECT 1;
++
++--connection node_2
++SELECT DEFINER= 'root@localhost', ORIGINATOR = 1, STATUS = 'SLAVESIDE_DISABLED', EVENT_TYPE = 'ONE TIME', ON_COMPLETION = 'NOT PRESERVE' FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++
++--connection node_1
++ALTER EVENT event1 DISABLE;
++
++--connection node_2
++# The definition on node 2 should still say SLAVESIDE_DISABLED
++SELECT DEFINER= 'root@localhost', ORIGINATOR = 1, STATUS = 'SLAVESIDE_DISABLED', EVENT_TYPE = 'ONE TIME', ON_COMPLETION = 'NOT PRESERVE' FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++
++#
++# Expired event should be dropped from the slave
++#
++
++--connection node_2
++SET GLOBAL event_scheduler = ON;
++CREATE EVENT event2 ON SCHEDULE AT CURRENT_TIMESTAMP ON COMPLETION NOT PRESERVE DO SELECT 1;
++--sleep 1
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event2';
++
++#
++# DROP EVENT causes event to be dropped everywhere
++#
++
++--connection node_1
++DROP EVENT event1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1';
++
++# Cleanup
++
++--connection node_2
++--eval SET GLOBAL event_scheduler = $event_scheduler_orig;
+diff --git a/mysql-test/suite/galera/t/galera_fk_cascade_delete.test b/mysql-test/suite/galera/t/galera_fk_cascade_delete.test
+new file mode 100644
+index 0000000..9b79b4c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_cascade_delete.test
+@@ -0,0 +1,41 @@
++#
++# Test Foreign Key Cascading DELETEs
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE grandparent (
++    id INT NOT NULL PRIMARY KEY
++) ENGINE=InnoDB;
++
++CREATE TABLE parent (
++    id INT NOT NULL PRIMARY KEY,
++    grandparent_id INT,
++    FOREIGN KEY (grandparent_id)
++        REFERENCES grandparent(id)
++        ON DELETE CASCADE
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT NOT NULL PRIMARY KEY, 
++    parent_id INT,
++    FOREIGN KEY (parent_id) 
++        REFERENCES parent(id)
++        ON DELETE CASCADE
++) ENGINE=InnoDB;
++
++INSERT INTO grandparent VALUES (1),(2);
++INSERT INTO parent VALUES (1,1), (2,2);
++INSERT INTO child VALUES (1,1), (2,2);
++
++--connection node_2
++DELETE FROM grandparent WHERE id = 1;
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM parent WHERE grandparent_id = 1;
++SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1;
++
++DROP TABLE child;
++DROP TABLE parent;
++DROP TABLE grandparent;
+diff --git a/mysql-test/suite/galera/t/galera_fk_cascade_update.test b/mysql-test/suite/galera/t/galera_fk_cascade_update.test
+new file mode 100644
+index 0000000..e736803
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_cascade_update.test
+@@ -0,0 +1,41 @@
++#
++# Test Foreign Key Cascading UPDATEs
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE grandparent (
++    id INT NOT NULL PRIMARY KEY
++) ENGINE=InnoDB;
++
++CREATE TABLE parent (
++    id INT NOT NULL PRIMARY KEY,
++    grandparent_id INT,
++    FOREIGN KEY (grandparent_id)
++        REFERENCES grandparent(id)
++        ON UPDATE CASCADE
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT NOT NULL PRIMARY KEY, 
++    grandparent_id INT,
++    FOREIGN KEY (grandparent_id)
++        REFERENCES parent(grandparent_id)
++        ON UPDATE CASCADE
++) ENGINE=InnoDB;
++
++INSERT INTO grandparent VALUES (1),(2);
++INSERT INTO parent VALUES (1,1), (2,2);
++INSERT INTO child VALUES (1,1), (2,2);
++
++--connection node_2
++UPDATE grandparent SET id = 3 WHERE id = 1;
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM parent WHERE grandparent_id = 3;
++SELECT COUNT(*) = 1 FROM child WHERE grandparent_id = 3;
++
++DROP TABLE child;
++DROP TABLE parent;
++DROP TABLE grandparent;
+diff --git a/mysql-test/suite/galera/t/galera_fk_conflict.test b/mysql-test/suite/galera/t/galera_fk_conflict.test
+new file mode 100644
+index 0000000..cb6f95e
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_conflict.test
+@@ -0,0 +1,41 @@
++#
++# Test two transactions on separate nodes which conflict on a FK
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE parent (
++    id INT PRIMARY KEY,
++    KEY (id)
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT PRIMARY KEY,
++    parent_id INT,
++    FOREIGN KEY (parent_id) 
++        REFERENCES parent(id)
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (1), (2);
++INSERT INTO child VALUES (1,1);
++
++--connection node_1
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++DELETE FROM parent WHERE id = 2;
++
++--connection node_2
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO child VALUES (2, 2);
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/t/galera_fk_mismatch.test b/mysql-test/suite/galera/t/galera_fk_mismatch.test
+new file mode 100644
+index 0000000..bded413
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_mismatch.test
+@@ -0,0 +1,38 @@
++#
++# Test the operation where the definition of the FK is different from the one of the underlying key
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE parent (
++    id1 INT,
++    id2 INT,
++    PRIMARY KEY (id1, id2) /* Multipart PK */
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT PRIMARY KEY,
++    parent_id1 INT,
++    FOREIGN KEY (parent_id1) 
++        REFERENCES parent(id1) /* FK is subset of PK above */
++        ON UPDATE CASCADE
++        ON DELETE CASCADE
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (1, 2);
++INSERT INTO child VALUES (1, 1);
++
++--connection node_2
++UPDATE parent SET id1 = 3 WHERE id1 = 1;
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM child WHERE parent_id1 = 3;
++
++DELETE FROM parent WHERE id1 = 3;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM child WHERE parent_id1 = 3;
++
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/t/galera_fk_multicolumn.test b/mysql-test/suite/galera/t/galera_fk_multicolumn.test
+new file mode 100644
+index 0000000..ad42f65
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_multicolumn.test
+@@ -0,0 +1,42 @@
++#
++# Test UPDATE on multiple columns with multiple FKs
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t0 (
++    f1 INT PRIMARY KEY,
++    f2 INT UNIQUE
++);
++
++CREATE TABLE t1 (
++    f1 INT PRIMARY KEY,
++    FOREIGN KEY (f1)
++        REFERENCES t0(f1)
++        ON UPDATE CASCADE
++);
++
++CREATE TABLE t2 (
++    f2 INT PRIMARY KEY,
++    FOREIGN KEY (f2)
++        REFERENCES t0(f2)
++        ON UPDATE CASCADE
++);
++
++INSERT INTO t0 VALUES (0, 0);
++INSERT INTO t1 VALUES (0);
++INSERT INTO t2 VALUES (0);
++
++--connection node_2
++UPDATE t0 SET f1 = 1, f2 = 2;
++
++--connection node_1
++SELECT f1 = 1 FROM t1 WHERE f1 = 1;
++SELECT f2 = 2 FROM t2 WHERE f2 = 2;
++SELECT f1 = 1 FROM t1;
++SELECT f2 = 2 FROM t2;
++
++DROP TABLE t2;
++DROP TABLE t1;
++DROP TABLE t0;
+diff --git a/mysql-test/suite/galera/t/galera_fk_multitable.test b/mysql-test/suite/galera/t/galera_fk_multitable.test
+new file mode 100644
+index 0000000..6adfb81
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_multitable.test
+@@ -0,0 +1,32 @@
++#
++# Test multi-table DELETE in the presence of FKs
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t0 (
++    f0 INT PRIMARY KEY
++);
++
++CREATE TABLE t1 (
++    f1 INT PRIMARY KEY,
++    f0 INTEGER,
++    FOREIGN KEY (f0)
++        REFERENCES t0(f0)
++        ON DELETE CASCADE
++);
++
++INSERT INTO t0 VALUES (0), (1);
++INSERT INTO t1 VALUES (0, 0);
++INSERT INTO t1 VALUES (1, 0);
++
++--connection node_2
++DELETE t0.*, t1.* FROM t0, t1 WHERE t0.f0 = 0 AND t1.f1 = 0;
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM t0;
++SELECT COUNT(*) = 0 FROM t1;
++
++DROP TABLE t1;
++DROP TABLE t0;
+diff --git a/mysql-test/suite/galera/t/galera_fk_no_pk.test b/mysql-test/suite/galera/t/galera_fk_no_pk.test
+new file mode 100644
+index 0000000..d1f9c26
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_no_pk.test
+@@ -0,0 +1,37 @@
++#
++# Test foreign keys if no PK is present
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE parent (
++    id INT,
++    KEY (id)
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT,
++    parent_id INT,
++    FOREIGN KEY (parent_id) 
++        REFERENCES parent(id)
++      ON UPDATE CASCADE
++      ON DELETE CASCADE
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (1), (1), (2), (2);
++INSERT INTO child VALUES (1,1), (2,2), (1,1), (2,2);
++
++--connection node_2
++DELETE FROM parent WHERE id = 1;
++SELECT COUNT(*) = 0 FROM child WHERE id = 1;
++
++--connection node_1
++UPDATE parent SET id = 3 WHERE id = 2;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1;
++SELECT parent_id = 3 FROM child WHERE id = 2;
++
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/t/galera_fk_selfreferential.test b/mysql-test/suite/galera/t/galera_fk_selfreferential.test
+new file mode 100644
+index 0000000..e2c1900
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_selfreferential.test
+@@ -0,0 +1,24 @@
++#
++# Test self-referential foreign keys
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (
++    f1 INT NOT NULL PRIMARY KEY,
++    f2 INT,
++    FOREIGN KEY (f2)
++        REFERENCES t1(f1)
++        ON DELETE CASCADE
++) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1, 1), (2, 1);
++
++--connection node_2
++DELETE FROM t1 WHERE f1 = 1;
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_fk_setnull.test b/mysql-test/suite/galera/t/galera_fk_setnull.test
+new file mode 100644
+index 0000000..46ba82d
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fk_setnull.test
+@@ -0,0 +1,36 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE parent (
++    id INT NOT NULL,
++    PRIMARY KEY (id)
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT, 
++    parent_id INT,
++    FOREIGN KEY (parent_id) 
++        REFERENCES parent(id)
++      ON UPDATE SET NULL
++      ON DELETE SET NULL
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (1),(2);
++INSERT INTO child VALUES (1,1),(2,2);
++
++--connection node_2
++DELETE FROM parent WHERE id = 1;
++SELECT parent_id IS NULL FROM child WHERE id = 1;
++
++--connection node_1
++SELECT parent_id IS NULL FROM child WHERE id = 1;
++
++UPDATE parent SET id = 3 WHERE id = 2;
++SELECT parent_id IS NULL FROM child WHERE id = 2;
++
++--connection node_2
++SELECT parent_id IS NULL FROM child WHERE id = 2;
++
++--connection node_1
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/t/galera_ftwrl.test b/mysql-test/suite/galera/t/galera_ftwrl.test
+new file mode 100644
+index 0000000..db9bd13
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ftwrl.test
+@@ -0,0 +1,39 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# At this time, issing a FLUSH TABLES WITH READ LOCK causes SELECT and SHOW to hang if 
++# casuality can not be ensured because another node issued a statement in the meantime
++# which could not be applied because FTWRL blocks the applier as well
++#
++# See LP bug 1271177
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options;`
++SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT1S";
++FLUSH TABLES WITH READ LOCK;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--error ER_LOCK_WAIT_TIMEOUT
++SHOW TABLES;
++
++--error ER_LOCK_WAIT_TIMEOUT
++SELECT * FROM t1;
++
++UNLOCK TABLES;
++
++SHOW TABLES;
++SELECT COUNT(*) = 1 FROM t1;
++
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = "$wsrep_provider_options_orig";
++--enable_query_log
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_fulltext.test b/mysql-test/suite/galera/t/galera_fulltext.test
+new file mode 100644
+index 0000000..aa93a33
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_fulltext.test
+@@ -0,0 +1,62 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# InnoDB FULLTEXT indexes
++#
++
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++#
++# Fulltext index creation causes the creation of multiple system tables
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(100), FULLTEXT (f2)) ENGINE=InnoDB;
++
++--connection node_2
++SELECT COUNT(*) = 13 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name LIKE 'test/%';
++
++#
++# Fulltext insertion causes a flurry of updates on those system tables
++#
++
++--connection node_1
++# Insert 10K rows
++INSERT INTO t1 (f2) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--connection node_2
++SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
++
++UPDATE t1 SET f2 = 'abcdefjhk';
++
++--connection node_1
++SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('abcdefjhk');
++
++--connection node_2
++
++DROP TABLE t1;
++
++#
++# Same on a table with no PK
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 VARCHAR(100), FULLTEXT (f1)) ENGINE=InnoDB;
++
++--connection node_2
++# We insert only 1K rows here, because updates without a PK are very slow
++INSERT INTO t1 (f1) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3;
++
++--connection node_1
++SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('foobarbaz');
++
++UPDATE t1 SET f1 = 'abcdefjhk';
++
++--connection node_2
++SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('abcdefjhk');
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_gcs_fc_limit.test b/mysql-test/suite/galera/t/galera_gcs_fc_limit.test
+new file mode 100644
+index 0000000..e15da0e
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_gcs_fc_limit.test
+@@ -0,0 +1,52 @@
++#
++# Test that under gcs.fc_limit=1 on the slave, transactions on the master can not commit.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
++
++# Block the slave applier thread
++FLUSH TABLES WITH READ LOCK;
++
++--connection node_1
++
++INSERT INTO t1 VALUES (2);
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++
++# This query will hang because flow control will kick in
++--send
++INSERT INTO t1 VALUES (5);
++--sleep 1
++
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++--connection node_1a
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'query end' AND INFO = 'INSERT INTO t1 VALUES (5)';
++
++--connection node_2
++# Unblock the slave applier thread
++UNLOCK TABLES;
++
++--connection node_1
++--reap
++
++INSERT INTO t1 VALUES (6);
++
++--connection node_2
++# Replication catches up and continues normally
++SELECT COUNT(*) = 6 FROM t1;
++
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_gcs_max_packet_size.cnf b/mysql-test/suite/galera/t/galera_gcs_max_packet_size.cnf
+new file mode 100644
+index 0000000..aae3fee
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_gcs_max_packet_size.cnf
+@@ -0,0 +1,5 @@
++!include ../galera_2nodes.cnf
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcs.max_packet_size=64'
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcs.max_packet_size=64'
+diff --git a/mysql-test/suite/galera/t/galera_gcs_max_packet_size.test b/mysql-test/suite/galera/t/galera_gcs_max_packet_size.test
+new file mode 100644
+index 0000000..cafd8ac
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_gcs_max_packet_size.test
+@@ -0,0 +1,25 @@
++#
++# Test fragmentation by setting gcs.max_packet_size to a low value
++# The actual setting is performed in galera_gcs_max_packet_size.cnf
++# as gcs.max_packet_size is not a dynamic variable
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 VARCHAR(512) UNIQUE) ENGINE=InnoDB;
++
++INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++INSERT INTO t2 VALUES (REPEAT('x', 512));
++
++--connection node_2
++SELECT COUNT(*) = 10000 FROM t1;
++SELECT LENGTH(f1) = 512 FROM t2 WHERE f1 = REPEAT('x', 512);
++
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_gtid-master.opt b/mysql-test/suite/galera/t/galera_gtid-master.opt
+new file mode 100644
+index 0000000..48e46d7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_gtid-master.opt
+@@ -0,0 +1 @@
++--gtid-mode=ON --log-bin --log-slave-updates --enforce-gtid-consistency
+diff --git a/mysql-test/suite/galera/t/galera_gtid.test b/mysql-test/suite/galera/t/galera_gtid.test
+new file mode 100644
+index 0000000..97e7d1f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_gtid.test
+@@ -0,0 +1,27 @@
++#
++# Test basic Galera operation under --gtid-mode=ON 
++#
++
++--source include/have_log_bin.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY);
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++UPDATE t1 SET f1 = 2;
++
++--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++
++--disable_query_log
++--eval SELECT '$gtid_executed_node2' = @@global.gtid_executed AS gtid_executed_equal;
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_insert_ignore.test b/mysql-test/suite/galera/t/galera_insert_ignore.test
+new file mode 100644
+index 0000000..4b4b0a6
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_insert_ignore.test
+@@ -0,0 +1,60 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_sync_wait_orig = (SELECT @@wsrep_sync_wait)
++SET GLOBAL wsrep_sync_wait = 7;
++
++--connection node_2
++SET GLOBAL wsrep_sync_wait = 7;
++
++
++#
++# INSERT IGNORE with PRIMARY KEY
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++INSERT IGNORE INTO t1 VALUES (1), (2);
++SELECT * FROM t1;
++
++--connection node_2
++SELECT * FROM t1;
++
++# 
++# INSERT IGNORE ... SELECT
++#
++
++--connection node_2
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (0), (2), (3);
++INSERT IGNORE INTO t1 SELECT f1 FROM t2;
++
++SELECT * FROM t1;
++--connection node_1
++SELECT * FROM t1;
++
++#
++# INSERT IGNORE with UNIQUE + NULLs
++#
++
++--connection node_2
++CREATE TABLE t3 (f1 INTEGER UNIQUE) Engine=InnoDB;
++INSERT INTO t3 VALUES (NULL);
++
++--connection node_1
++INSERT IGNORE INTO t3 VALUES (1), (NULL), (2);
++SELECT * FROM t3;
++
++--connection node_2
++SELECT * FROM t3;
++
++--eval SET GLOBAL wsrep_sync_wait = $wsrep_sync_wait_orig
++
++--connection node_1
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++--eval SET GLOBAL wsrep_sync_wait = $wsrep_sync_wait_orig
++
+diff --git a/mysql-test/suite/galera/t/galera_insert_multi.test b/mysql-test/suite/galera/t/galera_insert_multi.test
+new file mode 100644
+index 0000000..d62283a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_insert_multi.test
+@@ -0,0 +1,122 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Multi-row INSERT with a PK
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1),(2);
++
++--connection node_2
++INSERT INTO t1 VALUES (3),(4);
++
++--connection node_1
++SELECT COUNT(*) = 4 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 4 FROM t1;
++
++DROP TABLE t1;
++
++#
++# Multi-row INSERT without a PK
++#
++
++--connection node_2
++CREATE TABLE t1 (f1 INTEGER, KEY (f1)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1),(1);
++
++--connection node_1
++INSERT INTO t1 VALUES (2),(2);
++
++--connection node_2
++SELECT COUNT(*) = 4 FROM t1;
++
++--connection node_1
++SELECT COUNT(*) = 4 FROM t1;
++
++DROP TABLE t1;
++
++#
++# Error in the middle of a multi-row INSERT
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--error ER_DUP_ENTRY
++INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (1);
++
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++
++DROP TABLE t1;
++
++#
++# Deadlock
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1), (2);
++
++--connection node_2
++SET AUTOCOMMIT = OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (2), (1);
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++# Workaround for mysql-wsrep#39 Transaction receives deadlock error twice in row
++--error 0,ER_LOCK_DEADLOCK
++ROLLBACK;
++
++--error ER_DUP_ENTRY
++INSERT INTO t1 VALUES (1), (2);
++
++DROP TABLE t1;
++
++#
++# Rollback
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES (1), (2);
++
++--connection node_2
++START TRANSACTION;
++INSERT INTO t1 VALUES (2), (1);
++
++--connection node_1
++ROLLBACK;
++
++--connection node_2
++COMMIT;
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_1
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
++
++
++
++
++
++
++
+diff --git a/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.cnf b/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.cnf
+new file mode 100644
+index 0000000..85245ff
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.cnf
+@@ -0,0 +1,12 @@
++!include ../galera_2nodes.cnf
++
++[mysqld]
++wsrep_sst_method=xtrabackup-v2
++innodb_flush_log_at_trx_commit=0
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.test b/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.test
+new file mode 100644
+index 0000000..0783870
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.test
+@@ -0,0 +1,12 @@
++#
++# This test performs server kill and IST while innodb_flush_logs_on_trx_commit = 0
++# This confirms that IST can properly catch up even in the face of relaxed single-node durability
++#
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
+diff --git a/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf b/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf
+new file mode 100644
+index 0000000..db6b7d5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_2nodes.cnf
++
++# We do not set mysqldump-related SST options here because doing so on startup
++# causes the first MTR connection to be forefully dropped by Galera, which in turn confuses MTR
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_ist_mysqldump.test b/mysql-test/suite/galera/t/galera_ist_mysqldump.test
+new file mode 100644
+index 0000000..a9ff8c4
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_mysqldump.test
+@@ -0,0 +1,17 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_sst_set_mysqldump.inc
++
++# mysql-wsrep#33 - nnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno in trx_sys_update_wsrep_checkpoint with mysqldump IST
++# --source suite/galera/include/galera_st_disconnect_slave.inc
++
++# We set the required mysqldump SST options here so that they are used every time the server is restarted during the test
++--let $start_mysqld_params = --wsrep_sst_auth=sst:sst --wsrep_sst_method=mysqldump --wsrep-sst-receive-address=127.0.0.1:$NODE_MYPORT_2 --skip-grant-tables
++
++--source suite/galera/include/galera_st_shutdown_slave.inc
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
++
++--source suite/galera/include/galera_sst_restore.inc
+diff --git a/mysql-test/suite/galera/t/galera_ist_restart_joiner.cnf b/mysql-test/suite/galera/t/galera_ist_restart_joiner.cnf
+new file mode 100644
+index 0000000..10958aa
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_restart_joiner.cnf
+@@ -0,0 +1,4 @@
++!include ../galera_2nodes.cnf
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
+diff --git a/mysql-test/suite/galera/t/galera_ist_restart_joiner.test b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
+new file mode 100644
+index 0000000..69446f0
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
+@@ -0,0 +1,106 @@
++#
++# Test that a joiner performing IST can be killed and restarted with no adverse consequences.
++# This is achieved by using the recv_IST_after_apply_trx Galera dbug sync point to block IST after 
++# one transaction has been applied. When IST blocks, we kill and restart the joiner
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/have_debug_sync.inc
++--source suite/galera/include/galera_have_debug_sync.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
++INSERT INTO t1 VALUES (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'),(6, 'a');
++
++# Disconnect node #2
++--connection node_2
++--source suite/galera/include/galera_unload_provider.inc
++
++--connection node_1
++UPDATE t1 SET f2 = 'b' WHERE f1 > 1;
++
++# Wait until node #1 has left
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++UPDATE t1 SET f2 = 'c' WHERE f1 > 2;
++
++--connection node_2
++# Make sure IST will block ...
++SET GLOBAL wsrep_provider_options = 'dbug=d,recv_IST_after_apply_trx';
++SET SESSION wsrep_sync_wait = 0;
++
++
++# Write file to make mysql-test-run.pl expect the crash, but don't start it
++--let $_server_id= `SELECT @@server_id`
++--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
++--exec echo "wait" > $_expect_file_name
++
++--let KILL_NODE_PIDFILE = `SELECT @@pid_file`
++
++# ... and restart provider to force IST
++--echo Loading wsrep_provider ...
++--disable_query_log
++--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++# We can not use a wait_condition on SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS as such queries are blocked during IST
++# so we perform a simple sleep and SHOW instead
++
++--sleep 5
++SHOW STATUS LIKE 'wsrep_debug_sync_waiters';
++
++--connection node_1
++# Perform DML and DDL while IST is in progress
++--connection node_1
++UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
++CREATE TABLE t2 (f1 INTEGER);
++
++# Kill node #2 while IST is in progress
++--connection node_2
++
++# Kill the connected server
++--disable_reconnect
++
++--perl
++        my $pid_filename = $ENV{'KILL_NODE_PIDFILE'};
++        my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++        system("kill -9 $mysqld_pid");
++        exit(0);
++EOF
++
++--source include/wait_until_disconnected.inc
++
++--connection node_1
++--source include/wait_until_connected_again.inc
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++# Perform DML and DDL while node #2 is down
++UPDATE t1 SET f2 = 'e' WHERE f1 > 4;
++CREATE TABLE t3 (f1 INTEGER);
++
++--connection node_2
++
++--let $galera_wsrep_recover_server_id=2
++--source suite/galera/include/galera_wsrep_recover.inc
++
++--echo Starting server ...
++--source include/start_mysqld.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++--connection node_1
++UPDATE t1 SET f2 = 'f' WHERE f1 > 5;
++SELECT * FROM t1;
++
++--connection node_2
++SELECT * FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++SELECT COUNT(*) = 0 FROM t3;
++
++--connection node_1
++DROP TABLE t1, t2, t3;
+diff --git a/mysql-test/suite/galera/t/galera_ist_rsync.cnf b/mysql-test/suite/galera/t/galera_ist_rsync.cnf
+new file mode 100644
+index 0000000..bbe0f60
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_rsync.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_2nodes.cnf
++
++[mysqld]
++wsrep_sst_method=rsync
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_ist_rsync.test b/mysql-test/suite/galera/t/galera_ist_rsync.test
+new file mode 100644
+index 0000000..41d1a0c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_rsync.test
+@@ -0,0 +1,8 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_st_disconnect_slave.inc
++--source suite/galera/include/galera_st_shutdown_slave.inc
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
+diff --git a/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.cnf b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.cnf
+new file mode 100644
+index 0000000..21e5974
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_2nodes.cnf
++
++[mysqld]
++wsrep_sst_method=xtrabackup-v2
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test
+new file mode 100644
+index 0000000..8b399e7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test
+@@ -0,0 +1,9 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_st_disconnect_slave.inc
++--source suite/galera/include/galera_st_shutdown_slave.inc
++
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
+diff --git a/mysql-test/suite/galera/t/galera_kill_ddl.test b/mysql-test/suite/galera/t/galera_kill_ddl.test
+new file mode 100644
+index 0000000..3c2bce5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_kill_ddl.test
+@@ -0,0 +1,39 @@
++#
++# This test kill -9-s a slave while small updates have been performed on the master.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++
++# Enable the master to continue running during the split-brain situation that
++# occurs when the slave is killed
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++
++--connection node_2
++--source include/kill_galera.inc
++
++--connection node_1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++--connection node_2
++--source include/start_mysqld.inc
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_kill_largechanges.test b/mysql-test/suite/galera/t/galera_kill_largechanges.test
+new file mode 100644
+index 0000000..e9a32ce
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_kill_largechanges.test
+@@ -0,0 +1,43 @@
++#
++# This test kill -9-s a slave while a large update has been performed on the master. SST is performed.
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++# Enable the master to continue running during the split-brain situation that
++# occurs when the slave is killed
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
++CREATE TABLE t1 (f1 VARCHAR(128)) ENGINE=InnoDB;
++
++--connection node_2
++--source include/kill_galera.inc
++
++--connection node_1
++# We create a 128Mb (or so) transaction that is larger than gcache. The size of the gcache is not adjustable dynamically
++INSERT INTO t1 SELECT REPEAT('a', 128) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
++
++--connection node_2
++--source include/start_mysqld.inc
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++SELECT COUNT(*) = 1000000 FROM t1;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_kill_nochanges.test b/mysql-test/suite/galera/t/galera_kill_nochanges.test
+new file mode 100644
+index 0000000..1903df4
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_kill_nochanges.test
+@@ -0,0 +1,24 @@
++#
++# This test kill -9-s a slave while no updates have been performed on the master.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--source include/kill_galera.inc
++--source include/start_mysqld.inc
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++SELECT COUNT(*) = 1 FROM t1;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_kill_smallchanges.test b/mysql-test/suite/galera/t/galera_kill_smallchanges.test
+new file mode 100644
+index 0000000..d998032
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_kill_smallchanges.test
+@@ -0,0 +1,39 @@
++#
++# This test kill -9-s a slave while small updates have been performed on the master.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++
++# Enable the master to continue running during the split-brain situation that
++# occurs when the slave is killed
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++
++--connection node_2
++--source include/kill_galera.inc
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--source include/start_mysqld.inc
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++SELECT COUNT(*) = 1 FROM t1;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_lock_table.test b/mysql-test/suite/galera/t/galera_lock_table.test
+new file mode 100644
+index 0000000..bd58184
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_lock_table.test
+@@ -0,0 +1,43 @@
++#
++# Test that a LOCK TABLE on the slave will cause the applier thread to block, so no subsequent updates
++# are replicated on the slave until UNLOCK TABLE is issued.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_sync_wait_orig = `SELECT @@wsrep_sync_wait`
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++LOCK TABLE t1 READ;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++# We use a separate connection here so that we can SELECT from both tables
++# without running into "table t2 was not locked" error.
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++SET SESSION wsrep_sync_wait=0;
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++
++--connection node_2
++UNLOCK TABLES;
++
++--disable_query_log
++--eval SET SESSION wsrep_sync_wait=$wsrep_sync_wait_orig;
++--enable_query_log
++
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_log_bin-master.opt b/mysql-test/suite/galera/t/galera_log_bin-master.opt
+new file mode 100644
+index 0000000..8a755e9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_log_bin-master.opt
+@@ -0,0 +1 @@
++--log-bin --log-slave-updates
+diff --git a/mysql-test/suite/galera/t/galera_log_bin.test b/mysql-test/suite/galera/t/galera_log_bin.test
+new file mode 100644
+index 0000000..14f04e9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_log_bin.test
+@@ -0,0 +1,36 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test Galera with --log-bin --log-slave-updates .
++# This way the actual MySQL binary log is used,
++# rather than Galera's own implementation
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++CREATE TABLE t2 (id INT) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 2 FROM t2;
++
++--connection node_1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++FLUSH LOGS;
++# Use pos 120 in order to skip the header that contains the MySQL version number.
++# Otherwise, version number changes will cause the test to break
++SHOW BINLOG EVENTS IN '0.000002' FROM 120;
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++
++SHOW BINLOG EVENTS IN '0.000001' FROM 120;
++
++DROP TABLE t1;
++DROP TABLE t2;
++
+diff --git a/mysql-test/suite/galera/t/galera_log_output_csv-master.opt b/mysql-test/suite/galera/t/galera_log_output_csv-master.opt
+new file mode 100644
+index 0000000..2f71b14
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_log_output_csv-master.opt
+@@ -0,0 +1 @@
++--log-output=TABLE --log-queries-not-using-indexes --general-log --slow-query-log
+diff --git a/mysql-test/suite/galera/t/galera_log_output_csv.test b/mysql-test/suite/galera/t/galera_log_output_csv.test
+new file mode 100644
+index 0000000..0000939
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_log_output_csv.test
+@@ -0,0 +1,27 @@
++#
++# Test that --log-output=FILE works with Galera.
++# The relevant options are set using a -master.opt file
++# wsrep_replicate_myisam is not used as it crashes in MTR with mysql-wsrep#14
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++SELECT COUNT(*) > 0 FROM mysql.general_log;
++
++SELECT 1 = 1 FROM t1;
++SELECT COUNT(*) = 1 FROM mysql.slow_log WHERE sql_text = 'SELECT 1 = 1 FROM t1';
++
++--connection node_2
++
++# CREATE TABLE from master is also present in the slave query log, but is logged twice, mysql-wsrep#44
++SELECT COUNT(*) > 0 FROM mysql.general_log WHERE argument = 'CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB';
++
++SELECT 2 = 2 FROM t1;
++SELECT COUNT(*) = 1 FROM mysql.slow_log WHERE sql_text = 'SELECT 2 = 2 FROM t1';
++
++--connection node_1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_many_columns.test b/mysql-test/suite/galera/t/galera_many_columns.test
+new file mode 100644
+index 0000000..1961eae
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_many_columns.test
+@@ -0,0 +1,62 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--disable_query_log
++SET @create_var1 = "";
++--let $count = 1017
++while ($count)
++{
++  --eval SET @create_var1 = CONCAT(@create_var1, "f", $count, " VARCHAR(3) DEFAULT 'ABC', ")
++  --dec $count
++}
++
++--let $create_var = `SELECT @create_var1`
++--eval CREATE TABLE t1 ($create_var PRIMARY KEY (f1, f1017)) ENGINE=InnoDB;
++--enable_query_log
++
++INSERT INTO t1 (f1) VALUES (DEFAULT);
++
++--connection node_2
++SELECT f1 = 'ABC', f1017 = 'ABC' FROM t1;
++UPDATE t1 SET f1 = 'XYZ', f1017 = 'XYZ' ;
++
++--connection node_1
++SELECT f1 = 'XYZ', f1017 = 'XYZ' FROM t1 WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++
++
++# Deadlock
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'KLM' WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'CDE' WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
++COMMIT;
++
++--connection node_1
++--error ER_LOCK_DEADLOCK
++COMMIT;
++ROLLBACK;
++
++--connection node_2
++ROLLBACK;
++
++# Rollback
++
++--connection node_1
++START TRANSACTION;
++INSERT INTO t1 (f1, f1017) VALUES ('BCE','BCE');
++INSERT INTO t1 (f1, f1017) VALUES ('CED','CED');
++INSERT INTO t1 (f1, f1017) VALUES ('EDF','EDF');
++INSERT INTO t1 (f1, f1017) VALUES ('FED','FED');
++ROLLBACK;
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_many_indexes.test b/mysql-test/suite/galera/t/galera_many_indexes.test
+new file mode 100644
+index 0000000..e01d0b2
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_many_indexes.test
+@@ -0,0 +1,74 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 VARCHAR(767) PRIMARY KEY) ENGINE=InnoDB;
++
++# MySQL complains about multiple identical indexes on the same column
++--disable_warnings
++
++--let $count = 63
++while ($count)
++{
++  --disable_query_log
++  --eval SET @ddl_var1 = CONCAT("CREATE UNIQUE INDEX i", $count, " ON t1(f1)")
++  --let $ddl_var = `SELECT @ddl_var1`
++  --enable_query_log
++  --eval $ddl_var
++  --dec $count
++}
++--enable_warnings
++
++INSERT INTO t1 VALUES (REPEAT('a', 767));
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT LENGTH(f1) = 767 FROM t1;
++
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (PRIMARY) WHERE f1 = REPEAT('a', 767);
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (PRIMARY) WHERE f1 = REPEAT('a', 767);
++
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i1) WHERE f1 = REPEAT('a', 767);
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i1) WHERE f1 = REPEAT('a', 767);
++
++EXPLAIN SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i63) WHERE f1 = REPEAT('a', 767);
++SELECT COUNT(*) = 1 FROM t1 FORCE KEY (i63) WHERE f1 = REPEAT('a', 767);
++
++INSERT INTO t1 VALUES (REPEAT('b', 767));
++ANALYZE TABLE t1;
++
++--connection node_1
++SELECT COUNT(*) = 2 FROM t1;
++ANALYZE TABLE t1;
++DELETE FROM t1 WHERE f1 = REPEAT('b', 767);
++
++# Rollback
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++SELECT COUNT(*) = 1 FROM t1;
++INSERT INTO t1 (f1) VALUES (REPEAT('c', 767));
++ROLLBACK;
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_2
++START TRANSACTION;
++SET AUTOCOMMIT=OFF;
++SELECT COUNT(*) = 1 FROM t1;
++
++# Deadlock
++--connection node_1
++START TRANSACTION;
++--connection node_2
++START TRANSACTION;
++
++--connection node_1
++UPDATE t1 SET f1 = REPEAT('e', 767);
++--connection node_2
++UPDATE t1 SET f1 = REPEAT('f', 767);
++
++--connection node_1
++COMMIT;
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_many_rows.test b/mysql-test/suite/galera/t/galera_many_rows.test
+new file mode 100644
+index 0000000..0f4c4c0
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_many_rows.test
+@@ -0,0 +1,55 @@
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++--connection node_2
++SELECT COUNT(*) = 100000 FROM t1;
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++--connection node_1
++SELECT COUNT(*) = 200000 FROM t1;
++UPDATE t1 SET f2 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 200000 FROM t1 WHERE f2 = 1;
++
++# Rollback
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f2) SELECT a1.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++ROLLBACK;
++SELECT COUNT(*) = 200000 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 200000 FROM t1;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 2;
++ROLLBACK;
++
++--connection node_1
++START TRANSACTION;
++SELECT COUNT(*) = 200000 FROM t1;
++UPDATE t1 SET f2 = 3;
++
++--connection node_2
++START TRANSACTION;
++UPDATE t1 SET f2 = 4;
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_many_tables_nopk.test b/mysql-test/suite/galera/t/galera_many_tables_nopk.test
+new file mode 100644
+index 0000000..2496d14
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_many_tables_nopk.test
+@@ -0,0 +1,103 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# This test forces 1K tables without a PK to participate in a single transaction
++#
++
++#
++# First, create 1K tables
++#
++
++--connection node_1
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("CREATE TABLE t", $count, " (f1 INTEGER) ENGINE=InnoDB")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("INSERT INTO t", $count, " VALUES (1234)")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++#
++# Second, perform 1K updates
++#
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("UPDATE t", $count, " SET f1 = 1")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++COMMIT;
++
++# Third, confirm that all the inserts have arrived on the second node
++#
++
++--connection node_2
++CREATE TABLE sum_table (f1 INTEGER);
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("INSERT INTO sum_table SELECT COUNT(*) FROM t", $count)`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++SELECT SUM(f1) = 1000 FROM sum_table;
++
++#
++# Fourth, create a deadlock
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("UPDATE t", $count, " SET f1 = 2")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1000 SET f1 = 3;
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP SCHEMA test;
++CREATE SCHEMA test;
+diff --git a/mysql-test/suite/galera/t/galera_many_tables_pk.test b/mysql-test/suite/galera/t/galera_many_tables_pk.test
+new file mode 100644
+index 0000000..886cb7c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_many_tables_pk.test
+@@ -0,0 +1,98 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# This test forces 1K tables with a PK to participate in a single transaction
++#
++
++#
++# First, create 1K tables and make sure the DDLs are all propagated
++#
++
++--connection node_1
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("CREATE TABLE t", $count, " (f1 INTEGER AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++--connection node_2
++SELECT COUNT(*) = 1000 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't%';
++
++#
++# Second, create a transaction that uses all those tables
++# 
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("INSERT INTO t", $count, " VALUES (DEFAULT)")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++COMMIT;
++
++#
++# Third, confirm that all the inserts have arrived on the second node
++#
++
++--connection node_2
++CREATE TABLE sum_table (f1 INTEGER);
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("INSERT INTO sum_table SELECT COUNT(*) FROM t", $count)`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++SELECT SUM(f1) = 1000 FROM sum_table;
++
++#
++# Fourth, create a deadlock
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  --let $ddl_var = `SELECT CONCAT("UPDATE t", $count, " SET f1 = 2")`
++  --eval $ddl_var
++  --enable_query_log
++  --dec $count
++}
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1000 SET f1 = 3;
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP SCHEMA test;
++CREATE SCHEMA test;
+diff --git a/mysql-test/suite/galera/t/galera_migrate.cnf b/mysql-test/suite/galera/t/galera_migrate.cnf
+new file mode 100644
+index 0000000..dfaf4a6
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_migrate.cnf
+@@ -0,0 +1,47 @@
++#
++# This .cnf file starts 4 servers without enabling Galera.
++# The galera_migrate.test will set wsrep_provider and the other settings as needed.
++#
++
++!include include/default_mysqld.cnf
++
++[mysqld]
++binlog-format=row
++innodb_autoinc_lock_mode=2
++innodb_flush_log_at_trx_commit=2
++log-bin=mysqld-bin
++
++wsrep_node_address=127.0.0.1
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++[mysqld.1]
++
++[mysqld.2]
++
++[mysqld.3]
++
++[mysqld.4]
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_MYPORT_3= @mysqld.3.port
++NODE_MYSOCK_3= @mysqld.3.socket
++
++NODE_MYPORT_4= @mysqld.4.port
++NODE_MYSOCK_4= @mysqld.4.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++NODE_GALERAPORT_3= @mysqld.3.#galera_port
++NODE_GALERAPORT_4= @mysqld.4.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
++NODE_SSTPORT_3= @mysqld.3.#sst_port
++NODE_SSTPORT_4= @mysqld.4.#sst_port
+diff --git a/mysql-test/suite/galera/t/galera_migrate.test b/mysql-test/suite/galera/t/galera_migrate.test
+new file mode 100644
+index 0000000..5c34fd6
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_migrate.test
+@@ -0,0 +1,204 @@
++#
++# Execute a migration from MySQL replication to Galera replication.
++# The test starts with 4 stand-alone servers defined by galera_migrate.cnf and then
++# performs the following steps:
++#
++# 1. Begin with a single MySQL server
++# 2. Establish traditional MySQL master-slave replication
++# 3. Attach a new sever to serve as a MySQL replication slave
++# 4. Enable Galera on the new slave and create a single-node Galera cluster
++# 5. Attach a second Galera node
++# 6. Turn off the traditional replication parts of the system
++# 7. Continue replicating within Galera only
++#
++
++--source include/big_test.inc
++--source include/have_innodb.inc
++--source include/have_log_bin.inc
++
++#
++# Step #1 Begin with a single server
++#
++
++--connect node_1, 127.0.0.1, root, , test, $NODE_MYPORT_1
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++#
++# Step #2. Establish traditional MySQL replication
++#
++
++--connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2
++--disable_query_log
++--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT = $NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 2 FROM t1;
++--source include/wait_condition.inc
++
++#
++# Step #3. Attach a second slave, later to be converted to Galera
++#
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++--disable_query_log
++--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT = $NODE_MYPORT_1;
++--enable_query_log
++START SLAVE USER='root';
++
++--connection node_1
++INSERT INTO t1 VALUES (3);
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 3 FROM t1;
++--source include/wait_condition.inc
++
++#
++# Step #4. Convert this MySQL slave into a Galera node
++#
++
++--connection node_1
++INSERT INTO t1 VALUES (4);
++
++--connection node_3
++--disable_query_log
++--eval SET GLOBAL wsrep_provider='$WSREP_PROVIDER'
++--eval SET GLOBAL wsrep_provider_options='base_port=$NODE_GALERAPORT_3'
++--enable_query_log
++SET GLOBAL wsrep_cluster_address='gcomm://';
++
++--connection node_1
++INSERT INTO t1 VALUES (5);
++
++--connection node_3
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_1
++INSERT INTO t1 VALUES (6);
++
++#
++# Step #5. Attach a second Galera node using mysqldump SST
++#
++
++--connection node_3
++# We need a user with a password for mysqldump SST
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++SET GLOBAL wsrep_sst_auth = 'sst:sst';
++
++--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
++GRANT ALL PRIVILEGES ON *.* TO 'sst' IDENTIFIED BY 'sst';
++
++--disable_query_log
++--eval SET GLOBAL wsrep_sst_method = 'mysqldump';
++--eval SET GLOBAL wsrep_provider='$WSREP_PROVIDER'
++--eval SET GLOBAL wsrep_provider_options='base_port=$NODE_GALERAPORT_4'
++--eval SET GLOBAL wsrep_sst_receive_address = '127.0.0.2:$NODE_MYPORT_4';
++--eval SET GLOBAL wsrep_cluster_address='gcomm://127.0.0.1:$NODE_GALERAPORT_3'
++--enable_query_log
++
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT COUNT(*) = 6 FROM t1;
++--source include/wait_condition.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++
++#
++# Step #6. Turn off traditional replication
++#
++
++--connection node_2
++STOP SLAVE;
++RESET SLAVE ALL;
++
++--connection node_3
++STOP SLAVE;
++RESET SLAVE ALL;
++
++#
++# Step #7. Continue replicating within Galera only
++#
++
++# We need fresh connections due to galera#191
++
++--connect node_3a, 127.0.0.1, root, , test, $NODE_MYPORT_3
++INSERT INTO t1 VALUES (7);
++
++--connect node_4a, 127.0.0.1, root, , test, $NODE_MYPORT_4
++INSERT INTO t1 VALUES (8);
++
++--connection node_4a
++SELECT COUNT(*) = 8 FROM t1;
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_3a
++SELECT COUNT(*) = 8 FROM t1;
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 'Primary'  FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++#
++# Teardown
++# 
++
++--connection node_1
++DROP TABLE t1;
++
++--connection node_2
++DROP TABLE t1;
++
++--connection node_3
++SET GLOBAL wsrep_provider = 'none';
++SET GLOBAL wsrep_sst_auth = '';
++SET GLOBAL wsrep_provider_options = '';
++DROP TABLE t1;
++DROP USER sst;
++
++--connection node_4
++SET GLOBAL wsrep_provider = 'none';
++SET GLOBAL wsrep_sst_method = 'rsync';
++SET GLOBAL wsrep_provider_options = '';
++SET GLOBAL wsrep_sst_receive_address = 'AUTO';
++DROP TABLE t1;
++DROP USER sst;
++
++CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
+diff --git a/mysql-test/suite/galera/t/galera_multi_database.test b/mysql-test/suite/galera/t/galera_multi_database.test
+new file mode 100644
+index 0000000..6e06aaa
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_multi_database.test
+@@ -0,0 +1,43 @@
++#
++# Test that identical updates can be delivered to two separate
++# databases without this causing a certification conflict
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE DATABASE d1;
++CREATE TABLE d1.t1(f1 INTEGER) ENGINE=InnoDB;
++
++CREATE DATABASE d2;
++CREATE TABLE d2.t1(f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO d1.t1 VALUES (1);
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO d2.t1 VALUES (1);
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++COMMIT;
++
++SELECT COUNT(*) = 1 FROM d1.t1;
++SELECT COUNT(*) = 1 FROM d2.t1;
++
++--connection node_1
++
++SELECT COUNT(*) = 1 FROM d1.t1;
++SELECT COUNT(*) = 1 FROM d2.t1;
++
++DROP TABLE d1.t1;
++DROP TABLE d2.t1;
++
++DROP DATABASE d1;
++DROP DATABASE d2;
+diff --git a/mysql-test/suite/galera/t/galera_myisam_autocommit.test b/mysql-test/suite/galera/t/galera_myisam_autocommit.test
+new file mode 100644
+index 0000000..b01b5dc
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_myisam_autocommit.test
+@@ -0,0 +1,45 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# This tests simple autocommit replication of MyISAM tables. No updates arrive on the slave.
++#
++
++# Without a PK
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (2), (3);
++INSERT INTO t1 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM;
++INSERT INTO t2 VALUES (1);
++INSERT INTO t2 VALUES (2), (3);
++INSERT INTO t2 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++
++# Error
++--error ER_DUP_ENTRY
++INSERT INTO t2 VALUES (6), (1);
++
++# UPDATE
++
++UPDATE t1 SET f1 = 9;
++UPDATE t2 SET f1 = 9 WHERE f1 = 1;
++
++# DELETE
++
++DELETE FROM t1 WHERE f1 = 9;
++DELETE FROM t2 WHERE f1 = 9;
++
++# TRUNCATE
++
++TRUNCATE TABLE t1;
++TRUNCATE TABLE t1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_myisam_transactions.test b/mysql-test/suite/galera/t/galera_myisam_transactions.test
+new file mode 100644
+index 0000000..00e0bf3
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_myisam_transactions.test
+@@ -0,0 +1,36 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# This tests MyISAM tables in transactions. No MyISAM updates arrive on the slave, but InnoDB ones do.
++#
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
++CREATE TABLE t3 (f1 INTEGER) ENGINE=MyISAM;
++
++CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t3 VALUES (NEW.f1);
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++COMMIT;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++SELECT COUNT(*) = 0 FROM t2;
++
++--connection node_1
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++ROLLBACK;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++SELECT COUNT(*) = 0 FROM t2;
++
++DROP TABLE t1, t2, t3;
+diff --git a/mysql-test/suite/galera/t/galera_nopk_bit.test b/mysql-test/suite/galera/t/galera_nopk_bit.test
+new file mode 100644
+index 0000000..4292a6d
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_nopk_bit.test
+@@ -0,0 +1,46 @@
++#
++# This checks that even tables with a single BIT column are replicated properly without a PK
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 BIT) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),(0),(b'1');
++
++--connection node_2
++SELECT f1 IS NULL, f1 = b'1' FROM t1;
++
++DELETE FROM t1 WHERE f1 = b'1';
++UPDATE t1 SET f1 = b'1' WHERE f1 IS NULL;
++UPDATE t1 SET f1 = 1 WHERE f1 = b'0';
++
++--connection node_1
++SELECT f1 IS NULL, f1 = b'1' FROM t1;
++
++#
++# Provoke a conflict
++#
++
++--connection node_1
++CREATE TABLE t2 (f1 BIT) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (NULL);
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 0 WHERE f1 IS NULL;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 1 WHERE f1 IS NULL;
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_nopk_blob.test b/mysql-test/suite/galera/t/galera_nopk_blob.test
+new file mode 100644
+index 0000000..08e3b99
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_nopk_blob.test
+@@ -0,0 +1,46 @@
++#
++# This checks that even tables with a single BLOB column and no FK are replicated properly
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),('abc');
++
++--connection node_2
++SELECT f1 FROM t1;
++
++DELETE FROM t1 WHERE f1 IS NULL;
++UPDATE t1 SET f1 = 'xyz' WHERE f1 = 'abc';
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM t1;
++SELECT f1 = 'abc' FROM t1;
++
++#
++# Provoke a conflict
++#
++
++--connection node_1
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (NULL);
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'abc' WHERE f1 IS NULL;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'xyz' WHERE f1 IS NULL;
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_nopk_large_varchar.test b/mysql-test/suite/galera/t/galera_nopk_large_varchar.test
+new file mode 100644
+index 0000000..bb9bcd5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_nopk_large_varchar.test
+@@ -0,0 +1,50 @@
++#
++# This checks that even tables with a single long VARCHARcolumn and no FK are replicated properly
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++# From the Innodb manual: "The maximum row length, except for variable-length columns (VARBINARY, VARCHAR, BLOB and TEXT),
++# is slightly less than half of a database page. That is, the maximum row length is about 8000 bytes"
++
++CREATE TABLE t1 (f1 VARCHAR(8000)) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (NULL),(CONCAT(REPEAT('x', 7999), 'a'));
++
++--connection node_2
++SELECT LENGTH(f1) FROM t1;
++
++DELETE FROM t1 WHERE f1 IS NULL;
++UPDATE t1 SET f1 = CONCAT(REPEAT('x', 7999), 'b') WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM t1;
++SELECT LENGTH(f1) = 8000 FROM t1;
++SELECT f1 = CONCAT(REPEAT('x', 7999), 'b') FROM t1;
++
++#
++# Provoke a conflict
++#
++
++--connection node_1
++CREATE TABLE t2 (f1 BLOB) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (CONCAT(REPEAT('x', 7999), 'a'));
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'abc' WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t2 SET f1 = 'xyz' WHERE f1 = CONCAT(REPEAT('x', 7999), 'a');
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_nopk_unicode.test b/mysql-test/suite/galera/t/galera_nopk_unicode.test
+new file mode 100644
+index 0000000..e036e14
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_nopk_unicode.test
+@@ -0,0 +1,43 @@
++#
++# Test non-ascii data in table without a PK
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (
++      f1 VARCHAR(255),
++      KEY (f1)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++
++INSERT INTO t1 VALUES ('текст');
++
++--connection node_2
++SELECT f1 = 'текст' FROM t1;
++
++#
++# Provoke a conflict
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст2';
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст3';
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++SELECT f1 = 'текст2' FROM t1;
++SELECT f1 = 'текст2' FROM t1 WHERE f1 = 'текст2';
++
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test b/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test
+new file mode 100644
+index 0000000..7c49a57
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test
+@@ -0,0 +1,51 @@
++#
++# Test that a LOCK TABLE on the slave will cause all applier threads to block,
++# Even though the two INSERTS are independent transactions, the fact that t1 is locked
++# prevents the applier thread from committing the insert against t2, as commits are done
++# in order.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++--let $wsrep_sync_wait_orig = `SELECT @@wsrep_sync_wait`
++
++SET GLOBAL wsrep_slave_threads = 2;
++LOCK TABLE t1 READ;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++# We use a separate connection here so that we can SELECT from both tables
++# without running into "table t2 was not locked" error.
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++--sleep 1
++SET SESSION wsrep_sync_wait=0;
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%applied write set%';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Waiting for table level lock%';
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 0 FROM t2;
++
++--connection node_2
++UNLOCK TABLES;
++
++--connection node_2a
++--eval SET SESSION wsrep_sync_wait = $wsrep_sync_wait_orig;
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++SELECT COUNT(*) = 2  FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committed%';
++
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
+new file mode 100644
+index 0000000..a192044
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
+@@ -0,0 +1,50 @@
++##
++## This test tests parallel application of multiple auto-increment insert transactions
++##
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++# Create a second connection to node1 so that we can run transactions concurrently
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++--connection node_2
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++SET GLOBAL wsrep_slave_threads = 4;
++
++--connection node_1
++--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--connection node_1a
++--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--connection node_2
++--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--connection node_1
++--reap
++
++--connection node_1a
++--reap
++
++--connection node_2
++--reap
++SELECT COUNT(*) = 30000 FROM t1;
++SELECT COUNT(DISTINCT f1) = 30000 FROM t1;
++SELECT COUNT(*) = 5 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++
++--disable_query_log
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
++--enable_query_log
++
++--connection default
++DROP TABLE t1;
++DROP TABLE ten;
++
+diff --git a/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
+new file mode 100644
+index 0000000..cf984f9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
+@@ -0,0 +1,53 @@
++##
++## Tests the parallel application of many small-ish auto-increment insert transactions
++##
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++# Create a second connection to node1 so that we can run transactions concurrently
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
++--connection node_2
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++SET GLOBAL wsrep_slave_threads = 4;
++
++--connection node_1
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1;
++  --enable_query_log
++  --dec $count
++}
++
++--connection node_2
++--let $count = 1000
++while ($count)
++{
++  --disable_query_log
++  INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1;
++  --enable_query_log
++  --dec $count
++}
++
++SELECT COUNT(*) = 20000 FROM t1;
++SELECT COUNT(DISTINCT f1) = 20000 FROM t1;
++SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
++
++--disable_query_log
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
++--enable_query_log
++
++--connection default
++DROP TABLE t1;
++DROP TABLE ten;
++
+diff --git a/mysql-test/suite/galera/t/galera_parallel_simple.test b/mysql-test/suite/galera/t/galera_parallel_simple.test
+new file mode 100644
+index 0000000..b1dc14d
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_parallel_simple.test
+@@ -0,0 +1,45 @@
++#
++# Test that SHOW PROCESSLIST reports that two slave threads have been involved in applying
++# two independent transactions
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++
++CREATE TABLE t1 (id INT) ENGINE=InnoDB;
++CREATE TABLE t2 (id INT) ENGINE=InnoDB;
++
++--connection node_2
++SET GLOBAL wsrep_slave_threads = 2;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++--connection node_2
++
++SELECT COUNT(*) = 10 FROM t1;
++SELECT COUNT(*) = 10 FROM t2;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'committed%';
++
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_pc_ignore_sb.test b/mysql-test/suite/galera/t/galera_pc_ignore_sb.test
+new file mode 100644
+index 0000000..4be7331
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_pc_ignore_sb.test
+@@ -0,0 +1,35 @@
++#
++# Test pc.ignore_sb=true wsrep_provider option . Killing one node should leave the other running.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++
++SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
++
++--connection node_2
++--source include/kill_galera.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++DROP TABLE t1;
++
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++
++# Reset the master and restart the slave so that post-test checks can run
++
++SET GLOBAL wsrep_cluster_address = '';
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++--connection node_2
++--source include/start_mysqld.inc
++--source include/wait_until_connected_again.inc
+diff --git a/mysql-test/suite/galera/t/galera_pk_bigint_signed.test b/mysql-test/suite/galera/t/galera_pk_bigint_signed.test
+new file mode 100644
+index 0000000..12a8a8f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_pk_bigint_signed.test
+@@ -0,0 +1,46 @@
++#
++# PK that is a BIGINT SIGNED
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 BIGINT SIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES
++      (-9223372036854775808, 'min'),
++      (9223372036854775807, 'max')
++;
++
++--connection node_2
++SELECT * FROM t1;
++
++UPDATE t1 SET f2 = CONCAT(f2, '_');
++
++--connection node_1
++SELECT * FROM t1;
++
++#
++# Deadlock
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'foo' WHERE f1 = -9223372036854775808;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'bar' WHERE f1 = -9223372036854775808;
++
++--connection node_1
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_pk_bigint_unsigned.test b/mysql-test/suite/galera/t/galera_pk_bigint_unsigned.test
+new file mode 100644
+index 0000000..2bb02d5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_pk_bigint_unsigned.test
+@@ -0,0 +1,45 @@
++#
++# PK that is a BIGINT UNSIGNED
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 BIGINT UNSIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES
++      (18446744073709551615, 'max')
++;
++
++--connection node_2
++SELECT f1 = 18446744073709551615 FROM t1;
++
++UPDATE t1 SET f2 = CONCAT(f2, '_');
++
++--connection node_1
++SELECT f1 = 18446744073709551615 FROM t1;
++
++#
++# Deadlock
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'foo' WHERE f1 = 18446744073709551615;
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f2 = 'bar' WHERE f1 = 18446744073709551615;
++
++--connection node_1
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++SET AUTOCOMMIT=ON;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_query_cache-master.opt b/mysql-test/suite/galera/t/galera_query_cache-master.opt
+new file mode 100644
+index 0000000..18f8004
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_query_cache-master.opt
+@@ -0,0 +1,2 @@
++--query_cache_type=1
++
+diff --git a/mysql-test/suite/galera/t/galera_query_cache.test b/mysql-test/suite/galera/t/galera_query_cache.test
+new file mode 100644
+index 0000000..900faba
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_query_cache.test
+@@ -0,0 +1,67 @@
++--source include/have_query_cache.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Ensure that the query cache behaves properly with respect to Galera
++#
++# * in the absence of updates, the query cache does serve cached results
++# * any cache-invalidating query on the remote node also causes the local cache to be invalidated
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++RESET QUERY CACHE;
++FLUSH STATUS;
++
++#
++# 1. Cache works
++#
++
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++
++#
++# 2. Cache is invalidated by DML on remote node
++#
++
++--connection node_1
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++FLUSH STATUS;
++
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++
++#
++# 3. Cache is invalidated by DDL on remote node
++#
++
++--connection node_1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++--connection node_2
++FLUSH STATUS;
++
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Qcache_queries_in_cache';
++
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++SELECT COUNT(*) FROM t1;
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_read_only.test b/mysql-test/suite/galera/t/galera_read_only.test
+new file mode 100644
+index 0000000..828f35d
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_read_only.test
+@@ -0,0 +1,23 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Ensure that the read_only option does not apply to Galera appliers and that replication
++# continues, the way MySQL replication would.
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++SET GLOBAL read_only=TRUE;
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++SET GLOBAL read_only=FALSE;
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_repl_key_format_flat16.test b/mysql-test/suite/galera/t/galera_repl_key_format_flat16.test
+new file mode 100644
+index 0000000..8749c20
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_repl_key_format_flat16.test
+@@ -0,0 +1,34 @@
++#
++# Test repl.key_format = FLAT16 . Since it is very difficult to cause a collision on a 16-byte hash,
++# we simply verify that the option is settable and that replication works.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'repl.key_format=FLAT16';
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (123);
++
++CREATE TABLE t2 (f1 VARCHAR(256)) ENGINE=InnoDB;
++INSERT INTO t2 VALUES (REPEAT('a', 256));
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++UPDATE t1 SET f1 = 234;
++UPDATE t2 SET f1 = REPEAT('b', 256);
++
++--connection node_1
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 234;
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = REPEAT('b', 256);
++
++
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_repl_max_ws_size.test b/mysql-test/suite/galera/t/galera_repl_max_ws_size.test
+new file mode 100644
+index 0000000..255e292
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_repl_max_ws_size.test
+@@ -0,0 +1,27 @@
++#
++# Test repl.max_ws_size . A transaction larger than this size can not commit.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++
++CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB;
++
++SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512';
++
++--error ER_ERROR_DURING_COMMIT
++INSERT INTO t1 VALUES (REPEAT('a', 512));
++
++SELECT COUNT(*) = 0 FROM t1;
++
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++
++DROP TABLE t1;
++
++CALL mtr.add_suppression("WSREP: Maximum writeset size exceeded by");
++CALL mtr.add_suppression("WSREP: transaction size exceeded");
+diff --git a/mysql-test/suite/galera/t/galera_restart_nochanges.test b/mysql-test/suite/galera/t/galera_restart_nochanges.test
+new file mode 100644
+index 0000000..8eb7617
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_restart_nochanges.test
+@@ -0,0 +1,23 @@
++#
++# This test restarts a slave while no updates have been performed on the master. No SST is performed.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--source include/restart_mysqld.inc
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++SELECT COUNT(*) = 1 FROM t1;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_rsu_add_pk.test b/mysql-test/suite/galera/t/galera_rsu_add_pk.test
+new file mode 100644
+index 0000000..1a5501a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_rsu_add_pk.test
+@@ -0,0 +1,44 @@
++#
++# ALTER TABLE ... ADD PRIMARY KEY under Rolling Schema Upgrade
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++
++# Insert some values before the ALTER
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++# Insert more values while the ALTER is running
++--send INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++--connection node_2
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET GLOBAL wsrep_OSU_method = "TOI";
++
++# Insert values after the ALTER
++INSERT INTO t1 (f1) SELECT 200000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++
++SELECT COUNT(*) = 300000 FROM t1;
++SELECT MAX(f1) =  299999 FROM t1;
++
++--connection node_1
++--reap
++SELECT COUNT(*) = 300000 FROM t1;
++SELECT MAX(f1) =  299999 FROM t1;
++
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET GLOBAL wsrep_OSU_method = "TOI";
++
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_rsu_drop_pk.test b/mysql-test/suite/galera/t/galera_rsu_drop_pk.test
+new file mode 100644
+index 0000000..c3ccf89
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_rsu_drop_pk.test
+@@ -0,0 +1,58 @@
++#
++# ALTER TABLE ... DROP PRIMARY KEY under Rolling Schema Upgrade
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++
++# Insert some values before the ALTER
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++# Insert more values while the ALTER is running
++--send INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++--connection node_2
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 DROP PRIMARY KEY;
++SET GLOBAL wsrep_OSU_method = "TOI";
++
++# Insert even more data after the ALTER has completed
++INSERT INTO t1 (f1) SELECT 200000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++SELECT COUNT(*) = 300000 FROM t1;
++SELECT MAX(f1) =  299999 FROM t1;
++
++--connection node_1
++--reap
++SELECT COUNT(*) = 300000 FROM t1;
++SELECT MAX(f1) =  299999 FROM t1;
++
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 DROP PRIMARY KEY;
++SET GLOBAL wsrep_OSU_method = "TOI";
++
++# Insert some previously-conflicting values after the ALTER has been applied on all nodes.
++--connection node_2
++INSERT INTO t1 (f1) VALUES (1);
++INSERT INTO t1 (f1) VALUES (10);
++
++--connection node_1
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 1;
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 10;
++
++INSERT INTO t1 (f1) VALUES (100);
++INSERT INTO t1 (f1) VALUES (1000);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 100;
++SELECT COUNT(*) = 2 FROM t1 WHERE f1 = 1000;
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_rsu_error.test b/mysql-test/suite/galera/t/galera_rsu_error.test
+new file mode 100644
+index 0000000..b762d2b
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_rsu_error.test
+@@ -0,0 +1,31 @@
++#
++# Test DDL errors under Rolling Schema Upgrade
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t1 VALUES (1), (1);
++
++--connection node_2
++SET GLOBAL wsrep_OSU_method = "RSU";
++--error ER_DUP_ENTRY
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SET GLOBAL wsrep_OSU_method = "TOI";
++
++# The ALTER has no effect
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 't1';
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 3 FROM t1;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(3) = 4 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_rsu_simple.test b/mysql-test/suite/galera/t/galera_rsu_simple.test
+new file mode 100644
+index 0000000..ea0eec1
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_rsu_simple.test
+@@ -0,0 +1,35 @@
++#
++# Test Rolling Schema Upgrade
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++
++--connection node_2
++SET GLOBAL wsrep_OSU_method = "RSU";
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET GLOBAL wsrep_OSU_method = "TOI";
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++
++--connection node_1
++# The ALTER above is not visible on node_1
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++# The INSERT above is now visible on node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++INSERT INTO t1 (f1) VALUES (2);
++
++--connection node_1
++# The ALTER has not replicated
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++
++# However the INSERT above has
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_sbr.test b/mysql-test/suite/galera/t/galera_sbr.test
+new file mode 100644
+index 0000000..b598759
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sbr.test
+@@ -0,0 +1,27 @@
++#
++# Test behavior if the user attempts to use statement-based replication
++#
++# SBR is not currently supported but we expect that no crashes or binlog-related assertions will be triggered.
++# 
++
++--source include/have_innodb.inc
++--source include/galera_cluster.inc
++
++--connection node_1
++SET GLOBAL binlog_format = 'STATEMENT';
++SET SESSION binlog_format = 'STATEMENT';
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++SET SESSION binlog_format = 'MIXED';
++
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
++
++--connection node_1
++SET GLOBAL binlog_format = 'ROW';
+diff --git a/mysql-test/suite/galera/t/galera_sbr_binlog-master.opt b/mysql-test/suite/galera/t/galera_sbr_binlog-master.opt
+new file mode 100644
+index 0000000..beae84b
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sbr_binlog-master.opt
+@@ -0,0 +1 @@
++--log-bin
+diff --git a/mysql-test/suite/galera/t/galera_sbr_binlog.test b/mysql-test/suite/galera/t/galera_sbr_binlog.test
+new file mode 100644
+index 0000000..23e490a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sbr_binlog.test
+@@ -0,0 +1,28 @@
++#
++# Test behavior if the user attempts to use statement-based replication
++#
++# SBR is not currently supported but we expect that no crashes or binlog-related assertions will be triggered.
++# 
++
++--source include/have_log_bin.inc
++--source include/have_innodb.inc
++--source include/galera_cluster.inc
++
++--connection node_1
++SET GLOBAL binlog_format = 'STATEMENT';
++SET SESSION binlog_format = 'STATEMENT';
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++SET SESSION binlog_format = 'MIXED';
++
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
++
++--connection node_1
++SET GLOBAL binlog_format = 'ROW';
+diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test
+new file mode 100644
+index 0000000..4e53e96
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_split_brain.test
+@@ -0,0 +1,38 @@
++#
++# Confirm that with two nodes, killing one causes the other to stop accepting connections
++# The pc.ignore_sb=true wsrep_provider option is tested in the galera_kill_* tests.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++call mtr.add_suppression("WSREP: TO isolation failed for: ");
++
++--connection node_1
++--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
++
++--connection node_2
++--source include/kill_galera.inc
++
++--connection node_1
++--error ER_LOCK_DEADLOCK
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++
++# Reset the master and restart the slave so that post-test checks can run
++
++SET GLOBAL wsrep_cluster_address = '';
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++--source include/start_mysqld.inc
++--sleep 5
++--source include/wait_until_connected_again.inc
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++--sleep 5
++
++--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
++--source include/wait_until_connected_again.inc
+diff --git a/mysql-test/suite/galera/t/galera_sql_log_bin_zero.test b/mysql-test/suite/galera/t/galera_sql_log_bin_zero.test
+new file mode 100644
+index 0000000..b6965fa
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sql_log_bin_zero.test
+@@ -0,0 +1,25 @@
++#
++# Test SET SESSION sql_log_bin = 0 . We expect that unlogged updates will not be replicated
++# to the slave and that there will be no assertions in the process.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++
++SET SESSION sql_log_bin = 0;
++
++INSERT INTO t1 VALUES (1);
++
++SET SESSION sql_log_bin = 1;
++
++INSERT INTO t1 VALUES (2);
++
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 1;
++
++--connection node_1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_ssl.cnf b/mysql-test/suite/galera/t/galera_ssl.cnf
+new file mode 100644
+index 0000000..59ea286
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ssl.cnf
+@@ -0,0 +1,51 @@
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;socket.ssl=yes;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/galera-key.pem'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.2]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;socket.ssl=yes;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/galera-key.pem'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
+diff --git a/mysql-test/suite/galera/t/galera_ssl.test b/mysql-test/suite/galera/t/galera_ssl.test
+new file mode 100644
+index 0000000..8dc94dc
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_ssl.test
+@@ -0,0 +1,24 @@
++#
++# Test node connections over SSL. The accompanying galera_ssl.cnf has a customized
++# wsrep_provider_options setting that enables SSL.
++#
++# At this time, the actual operation of SSL is not visible only in the error log and not in SHOW STATUS.
++# So this test can only check that the cluster has formed and is replicating.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf b/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf
+new file mode 100644
+index 0000000..574ae28
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_2nodes.cnf
++
++# We do not set mysqldump-related SST options here because doing so on startup
++# causes the first MTR connection to be forefully dropped by Galera, which in turn confuses MTR
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump.test b/mysql-test/suite/galera/t/galera_sst_mysqldump.test
+new file mode 100644
+index 0000000..0b71715
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.test
+@@ -0,0 +1,18 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_sst_set_mysqldump.inc
++
++--source suite/galera/include/galera_st_disconnect_slave.inc
++
++# We set the required mysqldump SST options here so that they are used every time the server is restarted during the test
++--let $start_mysqld_params = --wsrep_sst_auth=sst:sst --wsrep_sst_method=mysqldump --wsrep-sst-receive-address=127.0.0.1:$NODE_MYPORT_2 --skip-grant-tables
++
++--source suite/galera/include/galera_st_shutdown_slave.inc
++--source suite/galera/include/galera_st_clean_slave.inc
++
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
++
++--source suite/galera/include/galera_sst_restore.inc
+diff --git a/mysql-test/suite/galera/t/galera_sst_rsync.cnf b/mysql-test/suite/galera/t/galera_sst_rsync.cnf
+new file mode 100644
+index 0000000..93981d9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_rsync.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_2nodes.cnf
++
++[mysqld]
++wsrep_sst_method=rsync
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_sst_rsync.test b/mysql-test/suite/galera/t/galera_sst_rsync.test
+new file mode 100644
+index 0000000..c682379
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_rsync.test
+@@ -0,0 +1,9 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_st_shutdown_slave.inc
++--source suite/galera/include/galera_st_clean_slave.inc
++
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
+diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf
+new file mode 100644
+index 0000000..47cb3e0
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf
+@@ -0,0 +1,13 @@
++!include ../galera_2nodes.cnf
++
++[mysqld]
++wsrep_sst_method=xtrabackup-v2
++wsrep_sst_auth="root:"
++wsrep_debug=ON
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
++
+diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test
+new file mode 100644
+index 0000000..c682379
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test
+@@ -0,0 +1,9 @@
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--source suite/galera/include/galera_st_shutdown_slave.inc
++--source suite/galera/include/galera_st_clean_slave.inc
++
++--source suite/galera/include/galera_st_kill_slave.inc
++--source suite/galera/include/galera_st_kill_slave_ddl.inc
+diff --git a/mysql-test/suite/galera/t/galera_status_cluster.test b/mysql-test/suite/galera/t/galera_status_cluster.test
+new file mode 100644
+index 0000000..3299613
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_status_cluster.test
+@@ -0,0 +1,18 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# A simple test for the wsrep_cluster_* status variables
++#
++
++--connection node_1
++
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++
++--connection node_2
++
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++
++
+diff --git a/mysql-test/suite/galera/t/galera_status_local_state.test b/mysql-test/suite/galera/t/galera_status_local_state.test
+new file mode 100644
+index 0000000..09cdb25
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_status_local_state.test
+@@ -0,0 +1,28 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Test wsrep_local_state . We can not reliably produce all possible statuses in MTR, but
++# we can at least test for the ones we can.
++#
++
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++SET GLOBAL wsrep_desync = 1;
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Donor/Desynced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++SET GLOBAL wsrep_desync = 0;
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++--source include/wait_condition.inc
++
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++
++
++
+diff --git a/mysql-test/suite/galera/t/galera_suspend_slave.test b/mysql-test/suite/galera/t/galera_suspend_slave.test
+new file mode 100644
+index 0000000..6330711
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_suspend_slave.test
+@@ -0,0 +1,51 @@
++##
++## This test tests that transactions on the master will fail if the slave
++## is made completely unresponsive by suspending the process. Resuming the
++## process should allow replication to continue to run.
++##
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++--let NODE_2_PIDFILE = `SELECT @@pid_file`
++--disconnect node_2
++
++--connection node_1
++--echo Suspending node_2 ...
++--perl
++      my $pid_filename = $ENV{'NODE_2_PIDFILE'};
++      my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++      system("kill -19 $mysqld_pid");
++      exit(0);
++EOF
++
++--error ER_UNKNOWN_COM_ERROR,ER_LOCK_WAIT_TIMEOUT
++INSERT INTO t1 VALUES (1);
++
++--echo Resuming node_2 ...
++--perl
++      my $pid_filename = $ENV{'NODE_2_PIDFILE'};
++      my $mysqld_pid = `cat $pid_filename`;
++        chomp($mysqld_pid);
++      system("kill -18 $mysqld_pid");
++      exit(0);
++EOF
++
++--sleep 10
++--source include/galera_wait_ready.inc
++INSERT INTO t1 VALUES (1);
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++
++--source include/galera_wait_ready.inc
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_toi_alter_auto_increment.test b/mysql-test/suite/galera/t/galera_toi_alter_auto_increment.test
+new file mode 100644
+index 0000000..641d210
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_alter_auto_increment.test
+@@ -0,0 +1,120 @@
++
++#
++# Test the operation of ALTER TABLE ... AUTO_INCREMENT
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
++
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++--connection node_2
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++ALTER TABLE t1 AUTO_INCREMENT = 1000;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++--connection node_1
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++SELECT MIN(f1) >= 1000, COUNT(*) = 20, COUNT(DISTINCT f1) = 20 FROM t1 WHERE f1 >= 1000;
++
++--connection node_2
++SELECT MIN(f1) >= 1000, COUNT(*) = 20, COUNT(DISTINCT f1) = 20 FROM t1 WHERE f1 >= 1000;
++
++#
++# AUTO_INCREMENT set to a value lower than the current one.
++# The ALTER does nothing, the sequence continues from the current maximum.
++#
++
++--connection node_1
++ALTER TABLE t1 AUTO_INCREMENT = 5;
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++--connection node_2
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++SELECT MIN(f1) >= 1000, COUNT(*) = 40, COUNT(DISTINCT f1) = 40 FROM t1 WHERE f1 >= 1000;
++
++--connection node_1
++SELECT MIN(f1) >= 1000, COUNT(*) = 40, COUNT(DISTINCT f1) = 40 FROM t1 WHERE f1 >= 1000;
++
++DROP TABLE t1;
++
++#
++# Under wsrep_auto_increment_control = OFF
++#
++
++--connection node_1
++--let $auto_increment_control_orig = `SELECT @@wsrep_auto_increment_control`
++--let $auto_increment_increment_node1 = `SELECT @@auto_increment_increment`
++--let $auto_increment_offset_node1 = `SELECT @@auto_increment_offset`
++
++# Restore stock MySQL defaults
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++
++#Open a fresh connection to node_1 so that the variables above take effect
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--connection node_2
++--let $auto_increment_increment_node2 = `SELECT @@auto_increment_increment`
++--let $auto_increment_offset_node2 = `SELECT @@auto_increment_offset`
++
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++
++#Open a fresh connection to node_2
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++
++--connection node_1a
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
++
++--connection node_2a
++
++ALTER TABLE t1 AUTO_INCREMENT=100;
++
++--connection node_1a
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++--connection node_2a
++INSERT INTO t1 (f2) SELECT 1 FROM ten;
++
++SELECT MIN(f1) = 100, MAX(f1) = 119, COUNT(f1) = 20, COUNT(DISTINCT f1) = 20 FROM t1;
++
++--connection node_1a
++SELECT MIN(f1) = 100, MAX(f1) = 119, COUNT(f1) = 20, COUNT(DISTINCT f1) = 20 FROM t1;
++
++DROP TABLE t1;
++
++#
++# Restore all variables as they were
++#
++
++--disable_query_log
++
++--connection node_1
++--eval SET GLOBAL wsrep_auto_increment_control = $auto_increment_control_orig
++--eval SET GLOBAL auto_increment_increment = $auto_increment_increment_node1
++--eval SET GLOBAL auto_increment_offset = $auto_increment_offset_node1
++
++--connection node_2
++--eval SET GLOBAL wsrep_auto_increment_control = $auto_increment_control_orig
++--eval SET GLOBAL auto_increment_increment = $auto_increment_increment_node2
++--eval SET GLOBAL auto_increment_offset = $auto_increment_offset_node2
++
++--enable_query_log
++
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_error.test b/mysql-test/suite/galera/t/galera_toi_ddl_error.test
+new file mode 100644
+index 0000000..c586d97
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ddl_error.test
+@@ -0,0 +1,29 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/big_test.inc
++
++#
++# Test the operation of DDLs that fail partway through
++#
++
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++
++# Insert 100K rows
++INSERT INTO t1 (f1) SELECT (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++# Insert one duplicate value
++INSERT INTO t1 (f1) SELECT MAX(f1) FROM t1;
++
++--connection node_2
++--error ER_DUP_ENTRY
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++SHOW CREATE TABLE t1;
++
++--connection node_1
++SHOW CREATE TABLE t1;
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_fk_insert.test b/mysql-test/suite/galera/t/galera_toi_ddl_fk_insert.test
+new file mode 100644
+index 0000000..1f44693
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ddl_fk_insert.test
+@@ -0,0 +1,70 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/big_test.inc
++
++#
++# This test creates a new FK constraint while concurrent INSERTS are running
++#
++
++CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE parent (
++    id INT PRIMARY KEY AUTO_INCREMENT,
++    f2 INTEGER,
++    KEY (id)
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT PRIMARY KEY AUTO_INCREMENT,
++    parent_id INT
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (DEFAULT, 0);
++
++--connection node_2
++--send INSERT INTO child (parent_id) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++--connection node_1a
++--send INSERT INTO parent (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++--send INSERT INTO parent (f2) SELECT 2 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
++
++--let $galera_connection_name = node_1b
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++--connection node_1b
++--sleep 2
++--send ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id);
++
++--connection node_1a
++--reap
++
++--connection node_1b
++--reap
++
++--connection node_2
++--reap
++
++--connection node_2a
++--reap
++
++--connection node_1
++SELECT COUNT(*) = 20001 FROM parent;
++SELECT COUNT(*) = 10000 FROM child;
++
++--connection node_2
++SELECT COUNT(*) = 20001 FROM parent;
++SELECT COUNT(*) = 10000 FROM child;
++
++DROP TABLE child;
++DROP TABLE parent;
++
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_locking.test b/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
+new file mode 100644
+index 0000000..24f918a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
+@@ -0,0 +1,70 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/have_debug.inc
++--source include/have_debug_sync.inc
++
++#
++# Test that DDL indeed causes all nodes to block so even unrelated updates
++# are not allowed to proceed. We block the DDL using DBUG_SYNC
++#
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++
++--connection node_1
++SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
++--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--let $galera_connection_name = node_1b
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--connection node_1a
++SET SESSION wsrep_sync_wait = 0;
++
++# Allowed
++SELECT COUNT(*) = 0 FROM t1;
++
++# Allowed
++SELECT COUNT(*) = 0 FROM t2;
++
++# Not allowed
++--error ER_LOCK_DEADLOCK
++INSERT INTO t1 VALUES (1);
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++
++# Allowed
++INSERT INTO t2 VALUES (1);
++
++# Hangs
++--send COMMIT;
++--sleep 1
++
++--connection node_1b
++SET SESSION wsrep_sync_wait = 0;
++
++# The Commit issued above is still not done
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
++SELECT COUNT(*) = 0 FROM t2;
++SET DEBUG_SYNC= 'now SIGNAL continue';
++
++--connection node_1a
++--reap
++
++--connection node_1
++--reap
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_nonconflicting.test b/mysql-test/suite/galera/t/galera_toi_ddl_nonconflicting.test
+new file mode 100644
+index 0000000..821f7a6
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ddl_nonconflicting.test
+@@ -0,0 +1,30 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# In this test, we simultaneously send two non-conflicting ALTER TABLE statements
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
++
++--connection node_2
++--send ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 (f1, f2) VALUES (DEFAULT, 123);
++
++--connection node_1
++--send CREATE UNIQUE INDEX i1 ON t1(f2);
++
++--connection node_2
++--reap
++INSERT INTO t1 (f1, f2) VALUES (DEFAULT, 234);
++
++SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_1
++--reap
++SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test b/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test
+new file mode 100644
+index 0000000..51eae70
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test
+@@ -0,0 +1,29 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# In this test, we send two ALTER TABLE statements that would only work if executed in the right order
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++INSERT INTO t1 VALUES (2, 3);
++
++--connection node_1
++ALTER TABLE t1 DROP COLUMN f2;
++INSERT INTO t1 VALUES (4);
++
++--connection node_2
++SHOW CREATE TABLE t1;
++SELECT COUNT(*) = 3 FROM t1;
++SELECT * FROM t1 ORDER BY f1;
++
++--connection node_1
++SHOW CREATE TABLE t1;
++SELECT COUNT(*) = 3 FROM t1;
++SELECT * FROM t1 ORDER BY f1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_toi_ftwrl.test b/mysql-test/suite/galera/t/galera_toi_ftwrl.test
+new file mode 100644
+index 0000000..4d0edef
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_ftwrl.test
+@@ -0,0 +1,22 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# At this time, issing a FLUSH TABLES WITH READ LOCK on one node does not prevent DDLs from other nodes
++# from proceeding. The locked node will apply the DDL after it has been unlocked
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++FLUSH TABLES WITH READ LOCK;
++
++--connection node_1
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++
++--connection node_2
++UNLOCK TABLES;
++SHOW CREATE TABLE t1;
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_toi_lock_exclusive.test b/mysql-test/suite/galera/t/galera_toi_lock_exclusive.test
+new file mode 100644
+index 0000000..3c66286
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_lock_exclusive.test
+@@ -0,0 +1,38 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Ensure that ALTER LOCK=EXCLUSIVE works under TOI. It is difficult to check that concurrent operations 
++# are truly not possible, but at least we expect no hangs or deadlocks
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++# Start a transaction that is concurrent to the DDL. This is not strictly necessary for this test
++# but does put more locks into play.
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (2);
++
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++--connection node_2a
++ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=EXCLUSIVE;
++
++# In Galera, a concurrent transaction aborts in the face of ALTER
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++--connection node_1
++INSERT INTO t1 VALUES (2, 2);
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_2
++INSERT INTO t1 VALUES (3, 3);
++SELECT COUNT(*) = 3 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_toi_lock_shared.test b/mysql-test/suite/galera/t/galera_toi_lock_shared.test
+new file mode 100644
+index 0000000..6857a0e
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_toi_lock_shared.test
+@@ -0,0 +1,23 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Ensure that ALTER LOCK=SHARED works under TOI. It is difficult to check that concurrent operations 
++# will be possible, but at least we expect no hangs or deadlocks
++#
++
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED;
++
++--connection node_1
++INSERT INTO t1 VALUES (2, 2);
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_2
++INSERT INTO t1 VALUES (3, 3);
++SELECT COUNT(*) = 3 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_transaction_read_only.test b/mysql-test/suite/galera/t/galera_transaction_read_only.test
+new file mode 100644
+index 0000000..386d73f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_transaction_read_only.test
+@@ -0,0 +1,58 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Ensure that transactions that do not write anything do not cause the wsrep_last_committed counter to advance
++#
++
++# Empty transaction
++
++--connection node_1
++CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
++
++--connection node_2
++--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++
++--connection node_1
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++COMMIT;
++
++--connection node_2
++--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++--disable_query_log
++--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before AS wsrep_last_committed_diff;
++--enable_query_log
++
++# START TRANSACTION READ ONLY
++
++--connection node_2
++--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++
++--connection node_1
++START TRANSACTION READ ONLY;
++SELECT COUNT(*) = 0 FROM t1;
++COMMIT;
++
++--connection node_2
++--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++--disable_query_log
++--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before AS wsrep_last_committed_diff;
++--enable_query_log
++
++# Ordinary transaction with only SELECTs
++
++--connection node_1
++START TRANSACTION;
++SELECT COUNT(*) = 0 FROM t1;
++COMMIT;
++
++--connection node_2
++--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++--disable_query_log
++--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before AS wsrep_last_committed_diff;
++--enable_query_log
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_transaction_replay.test b/mysql-test/suite/galera/t/galera_transaction_replay.test
+new file mode 100644
+index 0000000..d2c74ab
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_transaction_replay.test
+@@ -0,0 +1,63 @@
++#
++# This test tests the operation of transaction replay. If a potentially conflicting remote transaction arrives at
++# just the right time during the commit of a local transaction, the local transaction will be aborted and replayed.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/have_debug_sync.inc
++--source suite/galera/include/galera_have_debug_sync.inc
++
++--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
++INSERT INTO t1 VALUES (1, 'a');
++INSERT INTO t1 VALUES (2, 'a');
++
++--connection node_1
++SET AUTOCOMMIT=ON;
++START TRANSACTION;
++
++UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
++SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
++
++# Block the commit
++--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
++SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_enter_sync';
++
++--connection node_1
++--send COMMIT;
++
++# Wait until commit is blocked
++--connection node_1a
++SET SESSION wsrep_sync_wait = 0;
++--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters' AND VARIABLE_VALUE = 'apply_monitor_enter_sync'
++--source include/wait_condition.inc
++
++# Issue a conflicting update on node #2
++--connection node_2
++UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
++
++# Unblock the commit
++--connection node_1a
++SET GLOBAL wsrep_provider_options = 'dbug=';
++SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_enter_sync';
++
++# Commit succeeds
++--connection node_1
++--reap
++
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
++
++# wsrep_local_replays has increased by 1
++--let $wsrep_local_replays_new = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
++--disable_query_log
++--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 1 AS wsrep_local_replays;
++--enable_query_log
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_truncate.test b/mysql-test/suite/galera/t/galera_truncate.test
+new file mode 100644
+index 0000000..79f9bad
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_truncate.test
+@@ -0,0 +1,57 @@
++#
++# Test TRUNCATE
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Simple case
++#
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM t1;
++
++#
++# Table with no PK
++#
++
++--connection node_2
++CREATE TABLE t2 (f1 VARCHAR(255)) Engine=InnoDB;
++INSERT INTO t2 VALUES ('abc');
++
++--connection node_1
++TRUNCATE TABLE t2;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t2;
++
++#
++# Table with AUTO_INCREMENT. The AUTO_INCREMENT counter must be reset on all nodes
++#
++
++--connection node_1
++CREATE TABLE t3 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t3 VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
++
++CREATE TABLE t4 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB AUTO_INCREMENT=1234;
++INSERT INTO t4 VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
++
++TRUNCATE TABLE t3;
++TRUNCATE TABLE t4;
++
++--connection node_2
++SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t3', 't4');
++
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
++DROP TABLE t4;
+diff --git a/mysql-test/suite/galera/t/galera_truncate_temporary.test b/mysql-test/suite/galera/t/galera_truncate_temporary.test
+new file mode 100644
+index 0000000..3ad94eb
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_truncate_temporary.test
+@@ -0,0 +1,82 @@
++#
++# Test TRUNCATE on TEMPORARY tables. It should not be replicated
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TEMPORARY TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_2
++--error ER_NO_SUCH_TABLE
++SELECT * FROM t1;
++
++--connection node_1
++DROP TABLE t1;
++
++#
++# Test the case where a TEMPORARY table is masking an existing one
++#
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (2);
++
++SELECT f1 = 2 FROM t1;
++SELECT COUNT(*) = 1 FROM t1;
++
++TRUNCATE TABLE t1;
++
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT f1 = 1 FROM t1;
++
++--connection node_1
++
++DROP TABLE t1;
++SELECT COUNT(*) = 1 FROM t1;
++SELECT f1 = 1 FROM t1;
++
++TRUNCATE TABLE t1;
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++DROP TABLE t1;
++
++#
++# Test the case where one node has a TEMPORARY table but the TRUNCATE arrives from another node
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++TRUNCATE TABLE t1;
++
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++SELECT f1 = 2 FROM t1;
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
++
++SELECT COUNT(*) = 0 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_udf-master.opt b/mysql-test/suite/galera/t/galera_udf-master.opt
+new file mode 100644
+index 0000000..14dfe3e
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_udf-master.opt
+@@ -0,0 +1,2 @@
++$UDF_EXAMPLE_LIB_OPT
++--query_cache_type=1
+diff --git a/mysql-test/suite/galera/t/galera_unicode_identifiers.test b/mysql-test/suite/galera/t/galera_unicode_identifiers.test
+new file mode 100644
+index 0000000..2f255e9
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_unicode_identifiers.test
+@@ -0,0 +1,72 @@
++#
++# Test non-ascii table, column and index names
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_sync_wait_orig = (SELECT @@wsrep_sync_wait)
++SET GLOBAL wsrep_sync_wait = 7;
++
++--connection node_2
++SET GLOBAL wsrep_sync_wait = 7;
++
++--connection node_1
++
++# Spaces in identifiers
++
++CREATE DATABASE `database with space`;
++USE `database with space`;
++CREATE TABLE `table with space` (
++      `column with space` INTEGER AUTO_INCREMENT PRIMARY KEY,
++      `second column with space` INTEGER,
++      UNIQUE `index name with space` (`second column with space`)
++);
++INSERT INTO `table with space` VALUES (DEFAULT, 1);
++
++# Unicode identifiers
++
++CREATE DATABASE `база`;
++USE `база`;
++CREATE TABLE `таблица` (
++      `първа_колона` INTEGER PRIMARY KEY,
++      `втора_колона` INTEGER,
++      UNIQUE `индекс` (`втора_колона`)
++);
++
++INSERT INTO `таблица` VALUES (1, 1);
++
++# Without a PK
++
++CREATE DATABASE `втора база`;
++USE `втора база`;
++CREATE TABLE `втора таблица` (
++      `първа колона` INTEGER,
++      `втора колона` INTEGER,
++      KEY `първи индекс` (`първа колона`)
++);
++
++INSERT INTO `втора таблица` VALUES (1, 1);
++
++--connection node_2
++USE `database with space`;
++SELECT `second column with space` FROM `table with space`;
++
++USE `база`;
++SELECT * FROM `таблица`;
++
++USE `втора база`;
++SELECT `втора колона` FROM `втора таблица`;
++
++--eval SET GLOBAL wsrep_sync_wait = $wsrep_sync_wait_orig
++
++--connection node_1
++DROP TABLE `database with space`.`table with space`;
++DROP TABLE `база`.`таблица`;
++DROP TABLE `втора база`.`втора таблица`;
++
++DROP DATABASE `database with space`;
++DROP DATABASE `база`;
++DROP DATABASE `втора база`;
++--eval SET GLOBAL wsrep_sync_wait = $wsrep_sync_wait_orig
++
+diff --git a/mysql-test/suite/galera/t/galera_unicode_pk.test b/mysql-test/suite/galera/t/galera_unicode_pk.test
+new file mode 100644
+index 0000000..0d571f5
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_unicode_pk.test
+@@ -0,0 +1,64 @@
++#
++# Test non-ascii data in table where the PK is unicode
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (
++      f1 VARCHAR(255) PRIMARY KEY
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++
++INSERT INTO t1 VALUES ('текст');
++
++--connection node_2
++SELECT f1 = 'текст' FROM t1;
++
++#
++# Provoke a conflict
++#
++
++--connection node_1
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст2';
++
++--connection node_2
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++UPDATE t1 SET f1 = 'текст3';
++
++--connection node_1
++COMMIT;
++
++--connection node_2
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++SELECT f1 = 'текст2' FROM t1;
++SELECT f1 = 'текст2' FROM t1 WHERE f1 = 'текст2';
++
++#
++# Provoke a duplicate key error
++#
++
++--connection node_2
++START TRANSACTION;
++INSERT INTO t1 VALUES ('текст4');
++
++--connection node_1
++START TRANSACTION;
++INSERT INTO t1 VALUES ('текст4');
++
++--connection node_2
++COMMIT;
++
++--connection node_1
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++# Work around for mysql-wsrep#29 'Spurious deadlock error on a DROP TABLE'
++--error 0,ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_update_limit.test b/mysql-test/suite/galera/t/galera_update_limit.test
+new file mode 100644
+index 0000000..baacf2a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_update_limit.test
+@@ -0,0 +1,55 @@
++#
++# UPDATE LIMIT should not cause any issues with row-based Galera replication
++# regardless of the order in which the rows were updated
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# With a PK
++#
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
++INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t1 SELECT f1 FROM ten ORDER BY RAND();
++
++--connection node_2
++UPDATE IGNORE t1 SET f1 = FLOOR(1 + (RAND() * 10)) ORDER BY RAND() LIMIT 5;
++
++# Check that the sum of all elements and the max element are identical across nodes
++# as this will indicate that the same UPDATE was applied to both nodes
++
++--let $sum_rows = `SELECT SUM(f1) FROM t1`
++--let $max_row = `SELECT MAX(f1) FROM t1`
++
++--connection node_1
++--disable_query_log
++--eval SELECT (SELECT SUM(f1) FROM t1) = $sum_rows AS sum_matches;
++--eval SELECT f1 = $max_row AS max_matches FROM t1 WHERE f1 = $max_row;
++--enable_query_log
++
++DROP TABLE t1;
++
++#
++# Without a PK
++#
++
++CREATE TABLE t2 (f1 INTEGER) Engine=InnoDB;
++INSERT INTO t2 SELECT f1 FROM ten ORDER BY RAND();
++
++--connection node_2
++UPDATE IGNORE t2 SET f1 = FLOOR(1 + (RAND() * 10)) ORDER BY RAND() LIMIT 5;
++
++--let $sum_rows = `SELECT SUM(f1) FROM t2`
++
++--connection node_1
++--disable_query_log
++--eval SELECT (SELECT SUM(f1) FROM t2) = $sum_rows AS sum_matches;
++--enable_query_log
++
++DROP TABLE t2;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_v1_row_events-master.opt b/mysql-test/suite/galera/t/galera_v1_row_events-master.opt
+new file mode 100644
+index 0000000..dc82542
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_v1_row_events-master.opt
+@@ -0,0 +1 @@
++--log-bin-use-v1-row-events=1
+diff --git a/mysql-test/suite/galera/t/galera_v1_row_events.test b/mysql-test/suite/galera/t/galera_v1_row_events.test
+new file mode 100644
+index 0000000..0c0a044
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_v1_row_events.test
+@@ -0,0 +1,21 @@
++#
++# Test that Galera continues to run even with --log-bin-use-v1-row-events=1
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_1
++UPDATE t1 SET f1 = 2 WHERE f1 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_auto_inc_control_off.test b/mysql-test/suite/galera/t/galera_var_auto_inc_control_off.test
+new file mode 100644
+index 0000000..c0bbe5a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_auto_inc_control_off.test
+@@ -0,0 +1,105 @@
++#
++# Test wsrep_auto_increment_control = OFF
++# We issue two concurrent INSERTs and one will fail with a deadlock error
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $auto_increment_control_orig = `SELECT @@wsrep_auto_increment_control`
++
++#
++# Preserve existing variable values
++# 
++
++--connection node_1
++--let $auto_increment_increment_node1 = `SELECT @@auto_increment_increment`
++--let $auto_increment_offset_node1 = `SELECT @@auto_increment_offset`
++
++# Restore stock MySQL defaults 
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++
++#Open a fresh connection to node_1 so that the variables above take effect
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++
++--connection node_2
++--let $auto_increment_increment_node2 = `SELECT @@auto_increment_increment`
++--let $auto_increment_offset_node2 = `SELECT @@auto_increment_offset`
++
++SET GLOBAL wsrep_auto_increment_control = OFF;
++SET GLOBAL auto_increment_increment = 1;
++SET GLOBAL auto_increment_offset = 1;
++
++#Open a fresh connection to node_2
++--let $galera_connection_name = node_2a
++--let $galera_server_number = 2
++--source include/galera_connect.inc
++
++--connection node_1a
++SELECT @@auto_increment_increment = 1;
++SELECT @@auto_increment_offset = 1;
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, node VARCHAR(10)) ENGINE=InnoDB;
++
++#
++# We expect that SHOW CREATE TABLE on both nodes will return identical values
++#
++
++SHOW CREATE TABLE t1;
++
++--connection node_2a
++
++SHOW CREATE TABLE t1;
++
++--connection node_1a
++SELECT @@auto_increment_increment = 1;
++SELECT @@auto_increment_offset = 1;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (node) VALUES ('node1');
++SELECT f1 FROM t1;
++
++--connection node_2a
++SELECT @@auto_increment_increment = 1;
++SELECT @@auto_increment_offset = 1;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (node) VALUES ('node2');
++SELECT f1 FROM t1;
++
++--connection node_1a
++COMMIT;
++
++--connection node_2a
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++--connection node_1a
++SELECT * FROM t1;
++
++--connection node_2a
++SELECT * FROM t1;
++
++#
++# Restore all variables as they were
++#
++
++--disable_query_log
++
++--connection node_1
++--eval SET GLOBAL wsrep_auto_increment_control = $auto_increment_control_orig
++--eval SET GLOBAL auto_increment_increment = $auto_increment_increment_node1
++--eval SET GLOBAL auto_increment_offset = $auto_increment_offset_node1
++
++--connection node_2
++--eval SET GLOBAL wsrep_auto_increment_control = $auto_increment_control_orig
++--eval SET GLOBAL auto_increment_increment = $auto_increment_increment_node2
++--eval SET GLOBAL auto_increment_offset = $auto_increment_offset_node2
++
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_auto_inc_control_on.test b/mysql-test/suite/galera/t/galera_var_auto_inc_control_on.test
+new file mode 100644
+index 0000000..59f2615
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_auto_inc_control_on.test
+@@ -0,0 +1,53 @@
++#
++# Test the operation of wsrep_auto_increment_control = ON
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, node VARCHAR(10)) ENGINE=InnoDB;
++
++# auto_increment_increment is equal to the number of nodes
++# auto_increment_offset is equal to the ID of the node
++
++SELECT @@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size');
++SELECT @@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
++
++# Expect no conflicts
++--send INSERT INTO t1 VALUES (DEFAULT, 'node1');
++
++--connection node_2
++--send INSERT INTO t1 VALUES (DEFAULT, 'node2');
++
++--connection node_1
++--reap
++
++--connection node_2
++--reap
++
++SELECT @@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size');
++SELECT @@auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
++
++# Expect no conflicts
++--send INSERT INTO t1 VALUES (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2'), (DEFAULT, 'node2');
++
++--connection node_1
++--send INSERT INTO t1 VALUES (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1'), (DEFAULT, 'node1');
++
++--connection node_2
++--reap
++
++--connection node_1
++--reap
++
++--connection node_2
++SELECT COUNT(*) = 22 FROM t1;
++SELECT COUNT(DISTINCT f1) = 22 FROM t1;
++
++--connection node_1
++SELECT COUNT(*) = 22 FROM t1;
++SELECT COUNT(DISTINCT f1) = 22 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test b/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test
+new file mode 100644
+index 0000000..f7967da
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test
+@@ -0,0 +1,39 @@
++#
++# Test wsrep_certify_nonPK = OFF
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_certify_nonPK_orig = `SELECT @@wsrep_certify_nonPK`
++SET GLOBAL wsrep_certify_nonPK = OFF;
++
++--connection node_2
++SET GLOBAL wsrep_certify_nonPK = OFF;
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB /* Table has no primary key */;
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++# All DML without a PK is rejected with an error
++--error ER_LOCK_DEADLOCK
++INSERT INTO t1 VALUES (1), (2);
++
++# DML with a PK is allowed to proceed
++INSERT INTO t2 VALUES (1), (2);
++UPDATE t2 SET f1 = 3 WHERE f1 = 1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++SELECT COUNT(*) = 2 FROM t2;
++SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 3;
++
++--connection node_1
++--eval SET GLOBAL wsrep_certify_nonPK = $wsrep_certify_nonPK_orig
++
++--connection node_2
++--eval SET GLOBAL wsrep_certify_nonPK = $wsrep_certify_nonPK_orig
++
++DROP TABLE t1;
++DROP TABLE t2;
++
+diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test
+new file mode 100644
+index 0000000..609c62c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test
+@@ -0,0 +1,105 @@
++#
++# Check the handling of @@wsrep_cluster_address
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++#
++# Set to invalid value
++# 
++
++--connection node_1
++--let $wsrep_cluster_address_node1 = `SELECT @@wsrep_cluster_address`
++SET GLOBAL wsrep_cluster_address = 'foo://';
++
++# With wsrep_sync_wait, this returns an error
++--error ER_LOCK_WAIT_TIMEOUT
++SHOW STATUS;
++
++SET SESSION wsrep_sync_wait=0;
++
++--error ER_UNKNOWN_COM_ERROR
++SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
++
++# Must return 'OFF'
++SHOW STATUS LIKE 'wsrep_ready';
++
++# Must return 'Non-primary'
++SHOW STATUS LIKE 'wsrep_cluster_status';
++
++# Must return 0 = 'Initialized'
++SHOW STATUS LIKE 'wsrep_local_state';
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++
++--connection node_2
++--sleep 1
++# Node #2 thinks that it is now part of a single-node primary cluster 
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++
++#
++# Reset everything as it was
++#
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1';
++--enable_query_log
++
++--connection node_2
++SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++
++--source include/wait_until_connected_again.inc
++
++--connection node_1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++#
++# Set to invalid host
++#
++
++--connection node_1
++SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1';
++
++--error ER_UNKNOWN_COM_ERROR
++SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
++
++# Must return 'OFF'
++SHOW STATUS LIKE 'wsrep_ready';
++
++# Must return 'Non-primary'
++SHOW STATUS LIKE 'wsrep_cluster_status';
++
++# Must return 0 = 'Initialized'
++SHOW STATUS LIKE 'wsrep_local_state';
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++
++#
++# Reset everything as it was
++#
++
++--connection node_1
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1';
++--enable_query_log
++
++--connection node_2
++SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++--sleep 1
++
++--connection node_1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++CALL mtr.add_suppression("Backend not supported: foo");
++CALL mtr.add_suppression("Failed to initialize backend using 'foo");
++CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo");
++CALL mtr.add_suppression("gcs connect failed: Socket type not supported");
++CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7");
++CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)");
++CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110");
++CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)");
++CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'gcomm://192\\.0\\.2\\.1': -110 \\(Connection timed out\\)");
++CALL mtr.add_suppression("gcs connect failed: Connection timed out");
+diff --git a/mysql-test/suite/galera/t/galera_var_desync_on.test b/mysql-test/suite/galera/t/galera_var_desync_on.test
+new file mode 100644
+index 0000000..fb0fb9f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_desync_on.test
+@@ -0,0 +1,58 @@
++#
++# Test wsrep_desync = ON . Node should temporarily not participate in flow control
++# so even if fc_limit has been reached, the master should be able to continue to
++# commit transactions.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
++SET GLOBAL wsrep_desync = TRUE;
++
++# Block the slave applier thread 
++FLUSH TABLES WITH READ LOCK;
++
++--connection node_1
++
++# Without wsrep_desync = TRUE it would not be possible to perform 10 inserts on the master with gcs.fc_limit=1
++INSERT INTO t1 VALUES (2);
++INSERT INTO t1 VALUES (3);
++INSERT INTO t1 VALUES (4);
++INSERT INTO t1 VALUES (5);
++INSERT INTO t1 VALUES (6);
++INSERT INTO t1 VALUES (7);
++INSERT INTO t1 VALUES (8);
++INSERT INTO t1 VALUES (9);
++INSERT INTO t1 VALUES (10);
++--sleep 1
++
++--connection node_2
++SET SESSION wsrep_sync_wait = 0;
++# No updates have arrived after the FLUSH TABLES
++SELECT COUNT(*) = 1 FROM t1;
++
++# Resync the slave
++SET GLOBAL wsrep_desync = FALSE;
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
++--enable_query_log
++UNLOCK TABLES;
++
++SET SESSION wsrep_sync_wait = 1;
++# The slave is now fully caught up
++SELECT COUNT(*) = 10 FROM t1;
++
++--connection node_1
++INSERT INTO t1 VALUES (11);
++
++--connection node_2
++# Replication continues normally
++SELECT COUNT(*) = 11 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_fkchecks.test b/mysql-test/suite/galera/t/galera_var_fkchecks.test
+new file mode 100644
+index 0000000..c771b50
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_fkchecks.test
+@@ -0,0 +1,40 @@
++#
++# Test the operation on the foreign_key_checks variable
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE parent (
++    id INT PRIMARY KEY,
++    KEY (id)
++) ENGINE=InnoDB;
++
++CREATE TABLE child (
++    id INT PRIMARY KEY,
++    parent_id INT,
++    FOREIGN KEY (parent_id) 
++        REFERENCES parent(id)
++) ENGINE=InnoDB;
++
++INSERT INTO parent VALUES (1);
++INSERT INTO child VALUES (1,1);
++
++SET SESSION foreign_key_checks = 0;
++
++INSERT INTO child VALUES (2,2);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM child WHERE id = 2;
++
++--error ER_NO_REFERENCED_ROW_2
++INSERT INTO child VALUES (3,3);
++
++SET SESSION foreign_key_checks = 0;
++DELETE FROM parent;
++
++--connection node_1
++SELECT COUNT(*) = 0 FROM parent;
++
++DROP TABLE child;
++DROP TABLE parent;
+diff --git a/mysql-test/suite/galera/t/galera_var_innodb_disallow_writes.test b/mysql-test/suite/galera/t/galera_var_innodb_disallow_writes.test
+new file mode 100644
+index 0000000..c08483b
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_innodb_disallow_writes.test
+@@ -0,0 +1,33 @@
++#
++# This test checks that innodb_disallow_writes works as expected
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++# Open a separate connection to be used to run SHOW PROCESSLIST
++--let $galera_connection_name = node_1a
++--let $galera_server_number = 1
++--source include/galera_connect.inc
++--connection node_1a
++SET SESSION wsrep_sync_wait = 0;
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++SET GLOBAL innodb_disallow_writes=ON;
++--send INSERT INTO t1 VALUES (1);
++
++--connection node_1a
++let $wait_condition = SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'INSERT INTO t1 VALUES (1)' AND State = 'query end';
++--source include/wait_condition.inc
++
++SET GLOBAL innodb_disallow_writes=OFF;
++
++--connection node_1
++--reap
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_load_data_splitting.test b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test
+new file mode 100644
+index 0000000..0783dc8
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test
+@@ -0,0 +1,38 @@
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_load_data_splitting_orig = `SELECT @@wsrep_load_data_splitting`
++
++# Create a file for LOAD DATA with 95K entries
++--perl
++open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/galera_var_load_data_splitting.csv") or die;
++foreach  my $i (1..95000) {
++      print FILE "$i\n";
++}
++EOF
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++# Record wsrep_last_committed as it was before LOAD DATA
++--connection node_2
++--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++
++SET GLOBAL wsrep_load_data_splitting = TRUE;
++--disable_query_log
++--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/galera_var_load_data_splitting.csv' INTO TABLE t1;
++--enable_query_log
++
++--connection node_2
++--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
++
++SELECT COUNT(*) = 95000 FROM t1;
++
++# LOAD-ing 95K rows causes 10 commits to be registered
++--disable_query_log
++--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 10 AS wsrep_last_committed_diff;
++--enable_query_log
++
++--connection node_1
++--eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_max_ws_size.test b/mysql-test/suite/galera/t/galera_var_max_ws_size.test
+new file mode 100644
+index 0000000..bd98bab
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_max_ws_size.test
+@@ -0,0 +1,26 @@
++#
++# This test sets wsrep_max_ws_size to a very low value and checks that the transaction is rejected
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++call mtr.add_suppression('WSREP: transaction size limit.*');
++call mtr.add_suppression('WSREP: rbr write fail.*');
++call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
++call mtr.add_suppression('WSREP: transaction size exceeded.*');
++
++CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB;
++
++--let $wsrep_max_ws_size_orig = `SELECT @@wsrep_max_ws_size`
++SET GLOBAL wsrep_max_ws_size = 1024;
++
++--error ER_ERROR_DURING_COMMIT
++INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024));
++SELECT COUNT(*) = 0 FROM t1;
++
++--disable_query_log
++--eval SET GLOBAL wsrep_max_ws_size = $wsrep_max_ws_size_orig
++--enable_query_log
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_mysql_replication_bundle.test b/mysql-test/suite/galera/t/galera_var_mysql_replication_bundle.test
+new file mode 100644
+index 0000000..642d939
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_mysql_replication_bundle.test
+@@ -0,0 +1,30 @@
++#
++# Simple test for the operation on the wsrep-mysql-replication-bundle
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_mysql_replication_bundle_orig = `SELECT @@wsrep_mysql_replication_bundle`
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++
++SET GLOBAL wsrep_mysql_replication_bundle = 2;
++
++--connection node_1
++# This statement will not be replicated immediately
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_1
++--eval SET GLOBAL wsrep_mysql_replication_bundle = $wsrep_mysql_replication_bundle_orig
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_notify_cmd-master.opt b/mysql-test/suite/galera/t/galera_var_notify_cmd-master.opt
+new file mode 100644
+index 0000000..70dfc98
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_notify_cmd-master.opt
+@@ -0,0 +1 @@
++--wsrep_notify_cmd=$MYSQL_TEST_DIR/std_data/wsrep_notify.sh --wsrep-sync-wait=0
+diff --git a/mysql-test/suite/galera/t/galera_var_notify_cmd.test b/mysql-test/suite/galera/t/galera_var_notify_cmd.test
+new file mode 100644
+index 0000000..4fea69f
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_notify_cmd.test
+@@ -0,0 +1,14 @@
++#
++# Test wsrep_notify_cmd. We use a version of the support-files/wsrep_notify.sh script that writes
++# notifications into a table.
++#
++
++--source include/have_innodb.inc
++--source include/galera_cluster.inc
++
++--connection node_1
++SELECT COUNT(DISTINCT uuid) = 2 FROM mtr_wsrep_notify.membership;
++SELECT MAX(size) = 2 FROM mtr_wsrep_notify.status;
++SELECT COUNT(DISTINCT idx) = 2 FROM mtr_wsrep_notify.status;
++
++DROP SCHEMA mtr_wsrep_notify;
+diff --git a/mysql-test/suite/galera/t/galera_var_replicate_myisam_off.test b/mysql-test/suite/galera/t/galera_var_replicate_myisam_off.test
+new file mode 100644
+index 0000000..a981128
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_off.test
+@@ -0,0 +1,21 @@
++#
++# Simple test for wsrep-replicate-myisam = FALSE
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_replicate_myisam_orig = `SELECT @@wsrep_replicate_myisam`
++
++SET GLOBAL wsrep_replicate_myisam = FALSE;
++
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=MyISAM;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test
+new file mode 100644
+index 0000000..a09ba2e
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test
+@@ -0,0 +1,138 @@
++#
++# Simple test for wsrep-replicate-myisam = ON 
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_replicate_myisam_orig = `SELECT @@wsrep_replicate_myisam`
++
++--connection node_1
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++--connection node_2
++SET GLOBAL wsrep_replicate_myisam = TRUE;
++
++#
++# Simple INSERT
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=MyISAM;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t1 VALUES (2), (3);
++INSERT INTO t1 SELECT 4 FROM DUAL UNION ALL SELECT 5 FROM DUAL;
++
++--connection node_2
++SELECT COUNT(*) = 5 FROM t1;
++
++DROP TABLE t1;
++
++#
++# REPLACE
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(100)) ENGINE=MyISAM;
++INSERT INTO t1 VALUES (1, 'abc'),(2,'abc'), (3, 'xxx');
++REPLACE INTO t1 VALUES (1, 'klm'), (2,'xyz');
++REPLACE INTO t1 SELECT 3, 'yyy' FROM DUAL;
++
++--connection node_2
++SELECT COUNT(*) = 3 FROM t1;
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1 AND f2 = 'klm';
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2 AND f2 = 'xyz';
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 3 AND f2 = 'yyy';
++
++#
++# UPDATE
++#
++
++--connection node_1
++UPDATE t1 SET f2 = 'zzz' WHERE f2 = 'yyy';
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'zzz';
++
++#
++# DELETE
++#
++
++--connection node_1
++DELETE FROM t1 WHERE f2 = 'zzz';
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1 WHERE f2 = 'zzz';
++
++#
++# TRUNCATE
++#
++
++--connection node_1
++TRUNCATE TABLE t1;
++
++--connection node_2
++SELECT COUNT(*) = 0 FROM t1;
++DROP TABLE t1;
++
++#
++# Transaction
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
++CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++COMMIT;
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++
++#
++# Transaction rollback
++#
++
++--connection node_1
++START TRANSACTION;
++INSERT INTO t1 VALUES (2);
++INSERT INTO t2 VALUES (2);
++ROLLBACK;
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++SELECT COUNT(*) = 1 FROM t2;
++
++DROP TABLE t1;
++DROP TABLE t2;
++
++#
++# Transaction conflict
++#
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM;
++CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++--connection node_2
++# The MyISAM update is replicated immediately, so a duplicate key error happens even before the COMMIT
++--error ER_DUP_ENTRY
++INSERT INTO t1 VALUES (1);
++
++--connection node_1
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE t2;
++
++--connection node_1
++--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig
++
++--connection node_2
++--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig
+diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.test b/mysql-test/suite/galera/t/galera_var_slave_threads.test
+new file mode 100644
+index 0000000..a83924c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_slave_threads.test
+@@ -0,0 +1,70 @@
++#
++# This tests the very basic operations around wsrep-slave-threads
++# More complex scenarios will be tested separately in the context of
++# parallel replication
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++
++--connection node_1
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
++
++--connection node_2
++
++# Setting wsrep_slave_threads to zero triggers a warning
++SET GLOBAL wsrep_slave_threads = 0;
++SHOW WARNINGS;
++SELECT @@wsrep_slave_threads = 1;
++
++SET GLOBAL wsrep_slave_threads = 1;
++# There is a separate wsrep_aborter thread at all times
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++
++#
++# Increase the number of slave threads. The change takes effect immediately
++#
++
++SET GLOBAL wsrep_slave_threads = 64;
++--sleep 0.5
++
++--connection node_1
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++
++#
++# Reduce the number of slave threads. The change is not immediate -- a thread will only exit after a replication event
++#
++
++SET GLOBAL wsrep_slave_threads = 1;
++
++--connection node_1
++
++# Generate 64 replication events
++--let $count = 64
++while ($count)
++{
++  INSERT INTO t2 VALUES (DEFAULT);
++  --dec $count
++}
++
++--connection node_2
++SELECT COUNT(*) = 64 FROM t2;
++
++SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
++SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
++
++
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/galera_var_sync_wait.test b/mysql-test/suite/galera/t/galera_var_sync_wait.test
+new file mode 100644
+index 0000000..935c271
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_sync_wait.test
+@@ -0,0 +1,43 @@
++#
++# Simple test for the various levels of wsrep-sync-wait
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_sync_wait_orig = `SELECT @@wsrep_sync_wait`
++
++--connection node_1
++CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
++
++--connection node_2
++SET GLOBAL wsrep_sync_wait = 1;
++# Those statements should see the table
++SHOW TABLES LIKE '%t1';
++SELECT COUNT(*) = 0 FROM t1;
++
++--connection node_1
++CREATE TABLE t2 (f1 INT PRIMARY KEY) Engine=InnoDB;
++
++--connection node_2
++SET GLOBAL wsrep_sync_wait = 4;
++# This insert should see the table and succeed
++INSERT INTO t2 VALUES (1);
++
++--connection node_1
++CREATE TABLE t3 (f1 INT PRIMARY KEY) Engine=InnoDB;
++INSERT INTO t3 VALUES (1);
++
++--connection node_2
++SET GLOBAL wsrep_sync_wait = 2;
++# This statement should see and update 1 row
++--enable_info
++UPDATE t3 SET f1 = 2;
++--disable_info
++
++--connection node_2
++--eval SET GLOBAL wsrep_sync_wait = $wsrep_sync_wait_orig
++
++DROP TABLE t1;
++DROP TABLE t2;
++DROP TABLE t3;
+diff --git a/mysql-test/suite/galera/t/galera_var_wsrep_on_off.test b/mysql-test/suite/galera/t/galera_var_wsrep_on_off.test
+new file mode 100644
+index 0000000..783b787
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_var_wsrep_on_off.test
+@@ -0,0 +1,32 @@
++#
++# Test wsrep_on = OFF. Some events will not be replicated
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET SESSION wsrep_on = FALSE;
++
++# This statement will not be replicated
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++--connection node_1
++SET GLOBAL wsrep_on = TRUE;
++INSERT INTO t1 VALUES (3);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++# Middle insert is not replicated
++SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 2;
++
++# Final insert is replicated
++SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 3;
++
++DROP TABLE t1;
++
+diff --git a/mysql-test/suite/galera/t/galera_wan.cnf b/mysql-test/suite/galera/t/galera_wan.cnf
+new file mode 100644
+index 0000000..37ac58a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wan.cnf
+@@ -0,0 +1,14 @@
++!include ../galera_4nodes.cnf
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.segment=1'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.segment=1'
++
++[mysqld.3]
++wsrep_provider_options='base_port=@mysqld.3.#galera_port;gmcast.segment=2'
++
++[mysqld.4]
++wsrep_provider_options='base_port=@mysqld.4.#galera_port;gmcast.segment=3'
++
+diff --git a/mysql-test/suite/galera/t/galera_wan.test b/mysql-test/suite/galera/t/galera_wan.test
+new file mode 100644
+index 0000000..a8fd351
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wan.test
+@@ -0,0 +1,30 @@
++#
++# Test WAN replication and the gmcast.segment functionality.
++# The galera_wan.cnf file partitions 4 Galera nodes into 3 WAN segments
++#
++# We can not test any of the actual WAN optimizations from inside MTR and no 
++# status variables are provided. So we only check that simple replication works.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER);
++
++--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
++--connection node_3
++INSERT INTO t1 VALUES (1);
++CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside");
++
++--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
++--connection node_4
++SELECT VARIABLE_VALUE LIKE '%gmcast.segment = 3%' FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options';
++
++SELECT COUNT(*) = 1 FROM t1;
++
++DROP TABLE t1;
++
++CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside");
+diff --git a/mysql-test/suite/galera/t/galera_wsrep_desync_wsrep_on.test b/mysql-test/suite/galera/t/galera_wsrep_desync_wsrep_on.test
+new file mode 100644
+index 0000000..3c7988a
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wsrep_desync_wsrep_on.test
+@@ -0,0 +1,57 @@
++#
++# Test the wsrep_desync + wsrep_on method for schema upgrades discussed at
++# http://www.slideshare.net/Severalnines/schema-upgrades-codershippresodec2013 , slide 30
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE ten (f1 INTEGER);
++INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
++
++CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
++
++# Insert some values before the ALTER
++INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++--connection node_2
++SET GLOBAL wsrep_desync = TRUE;
++SET SESSION wsrep_on = FALSE;
++
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++
++SET SESSION wsrep_on = TRUE;
++SET GLOBAL wsrep_desync = FALSE;
++
++# Insert even more data after the ALTER has completed
++INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
++
++SELECT COUNT(*) = 200000 FROM t1;
++SELECT MAX(f1) =  199999 FROM t1;
++
++--connection node_1
++SELECT COUNT(*) = 200000 FROM t1;
++SELECT MAX(f1) =  199999 FROM t1;
++
++SET GLOBAL wsrep_desync = TRUE;
++SET SESSION wsrep_on = FALSE;
++
++ALTER TABLE t1 ADD PRIMARY KEY (f1);
++
++SET SESSION wsrep_on = TRUE;
++SET GLOBAL wsrep_desync = FALSE;
++
++# Insert some conflicting values after the ALTER has been applied on all nodes.
++
++--connection node_2
++--error ER_DUP_ENTRY
++INSERT INTO t1 (f1) VALUES (1);
++ 
++--connection node_1
++--error ER_DUP_ENTRY
++INSERT INTO t1 (f1) VALUES (100);
++
++DROP TABLE t1;
++DROP TABLE ten;
+diff --git a/mysql-test/suite/galera/t/galera_wsrep_new_cluster-master.opt b/mysql-test/suite/galera/t/galera_wsrep_new_cluster-master.opt
+new file mode 100644
+index 0000000..c31150c
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wsrep_new_cluster-master.opt
+@@ -0,0 +1 @@
++--wsrep-new-cluster
+diff --git a/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test b/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test
+new file mode 100644
+index 0000000..6ba8ce7
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test
+@@ -0,0 +1,24 @@
++#
++# Test the --wsrep-new-cluster option by putting it in the galera_wsrep_new_cluster-master.opt file
++#
++# In MTR, running two nodes, the result is two separate clusters of size 1
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++--connection node_2
++
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+diff --git a/mysql-test/suite/galera/t/galera_wsrep_provider_unset_set.test b/mysql-test/suite/galera/t/galera_wsrep_provider_unset_set.test
+new file mode 100644
+index 0000000..fe4c358
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_wsrep_provider_unset_set.test
+@@ -0,0 +1,41 @@
++#
++# Test that wsrep_provider can be unset and then set back to its original value
++# and replication will continue except for any updates made while the value was 'none'
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++--let $wsrep_provider_orig = `SELECT @@wsrep_provider`
++--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
++
++SET GLOBAL wsrep_provider='none';
++INSERT INTO t1 VALUES (2);
++
++--connection node_1
++INSERT INTO t1 VALUES (3);
++
++--connection node_2
++--disable_query_log
++--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++--source include/wait_until_connected_again.inc
++--source include/galera_wait_ready.inc
++
++INSERT INTO t1 VALUES (4);
++
++# Node #2 has all the inserts
++SELECT COUNT(*) = 4 FROM t1;
++
++--connection node_1
++# Node #1 is missing the insert made while Node #2 was not replicated
++SELECT COUNT(*) = 3 FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/galera_zero_length_column.test b/mysql-test/suite/galera/t/galera_zero_length_column.test
+new file mode 100644
+index 0000000..6ae81a8
+--- /dev/null
++++ b/mysql-test/suite/galera/t/galera_zero_length_column.test
+@@ -0,0 +1,41 @@
++#
++# Test columns with size zero. This is known to have tripped other storage engines.
++# Keys are not allowed on such columns
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY , f2 VARCHAR(0)) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 VARCHAR(0)) ENGINE=InnoDB;
++
++
++INSERT INTO t1 VALUES (1, NULL);
++INSERT INTO t1 VALUES (2, '');
++
++INSERT INTO t2 VALUES (NULL);
++INSERT INTO t2 VALUES ('');
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++SELECT f2 IS NULL FROM t1 WHERE f1 = 1;
++SELECT f2 = '' FROM t1 WHERE f1 = 2;
++
++SELECT COUNT(*) = 2 FROM t2;
++SELECT f1 IS NULL FROM t2 WHERE f1 IS NULL;
++SELECT f1 = '' FROM t2 WHERE f1 IS NOT NULL;
++
++UPDATE t1 SET f2 = '' WHERE f1 = 1;
++UPDATE t1 SET f2 = NULL WHERE f1 = 2;
++
++UPDATE t2 SET f1 = '' WHERE f1 IS NULL;
++
++--connection node_1
++SELECT f2 = '' FROM t1 WHERE f1 = 1;
++SELECT f2 IS NULL FROM t1 WHERE f1 = 2;
++
++SELECT COUNT(*) = 2 FROM t2 WHERE f1 = '';
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera/t/lp1276424.test b/mysql-test/suite/galera/t/lp1276424.test
+new file mode 100644
+index 0000000..a37e950
+--- /dev/null
++++ b/mysql-test/suite/galera/t/lp1276424.test
+@@ -0,0 +1,17 @@
++#
++# LP:1276424 Deadlock with insertion of NULL unique ke
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE t1 (f1 INT DEFAULT NULL, UNIQUE KEY i1 (f1)) ENGINE=InnoDB;
++
++INSERT INTO t1 VALUES (NULL);
++INSERT INTO t1 VALUES (NULL);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++SELECT f1 IS NULL FROM t1;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera/t/lp1347768.test b/mysql-test/suite/galera/t/lp1347768.test
+new file mode 100644
+index 0000000..96d4286
+--- /dev/null
++++ b/mysql-test/suite/galera/t/lp1347768.test
+@@ -0,0 +1,24 @@
++#
++# LP:1347768 Assertion failure in file ha_innodb.cc line 6759 
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++CREATE TABLE `r8kmb_redirect_links` (
++  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
++  `old_url` varchar(255) DEFAULT NULL,
++  `new_url` varchar(255) NOT NULL,
++  `referer` varchar(150) NOT NULL,
++  `comment` varchar(255) NOT NULL,
++  `published` tinyint(4) NOT NULL,
++  `created_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
++  `modified_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
++  PRIMARY KEY (`id`),
++  UNIQUE KEY `idx_link_old` (`old_url`),
++  KEY `idx_link_modifed` (`modified_date`)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8;
++
++INSERT INTO r8kmb_redirect_links VALUES (550,'http://mysite.com/images/download/ßуñûічýøù_ôþóþòір_þфõÑ.doc','','','',0,'2013-07-15 14:29:42','0000-00-00 00:00:00');
++
++DROP TABLE r8kmb_redirect_links;
+diff --git a/mysql-test/suite/galera/t/lp959512.test b/mysql-test/suite/galera/t/lp959512.test
+new file mode 100644
+index 0000000..bcc0db2
+--- /dev/null
++++ b/mysql-test/suite/galera/t/lp959512.test
+@@ -0,0 +1,26 @@
++#
++# LP#959512 IO cache not reset at trx cleanup if write set was empty Edit
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++DROP TABLE IF EXISTS variable;
++DROP TABLE IF EXISTS foo;
++CREATE TABLE variable (
++   name varchar(128) NOT NULL DEFAULT '' COMMENT 'The name of the variable.',
++   value longblob NOT NULL COMMENT 'The value of the variable.',
++    PRIMARY KEY (name)
++  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Named variable/value pairs created by Drupal core or any...';
++CREATE TABLE foo (a int);
++INSERT INTO variable (name, value) VALUES ('menu_expanded', 'a:0:{}');
++START TRANSACTION;
++SELECT 1 AS expression FROM variable variable
++   WHERE ( (name = 'menu_expanded') ) FOR UPDATE;
++UPDATE variable SET value='a:0:{}' WHERE ( (name = 'menu_expanded') );
++COMMIT;
++INSERT INTO foo VALUES (1);
++UPDATE foo SET a = 2 WHERE a = 1;
++
++DROP TABLE foo;
++DROP TABLE variable;
+diff --git a/mysql-test/suite/galera_3nodes/galera_3nodes.cnf b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
+new file mode 100644
+index 0000000..e837635
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
+@@ -0,0 +1,75 @@
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_provider_options='base_port=@mysqld.1.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.2]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.2.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[mysqld.3]
++binlog-format=row
++
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
++wsrep_provider_options='base_port=@mysqld.3.#galera_port'
++
++# enforce read-committed characteristics across the cluster
++wsrep_causal_reads=ON
++wsrep_sync_wait = 7
++
++wsrep_node_address=127.0.0.1
++wsrep_sst_receive_address=127.0.0.2:@mysqld.3.#sst_port
++wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
++
++# Required for Galera
++innodb_autoinc_lock_mode=2
++
++[ENV]
++NODE_MYPORT_1= @mysqld.1.port
++NODE_MYSOCK_1= @mysqld.1.socket
++
++NODE_MYPORT_2= @mysqld.2.port
++NODE_MYSOCK_2= @mysqld.2.socket
++
++NODE_MYPORT_3= @mysqld.3.port
++NODE_MYSOCK_3= @mysqld.3.socket
++
++NODE_GALERAPORT_1= @mysqld.1.#galera_port
++NODE_GALERAPORT_2= @mysqld.2.#galera_port
++NODE_GALERAPORT_3= @mysqld.3.#galera_port
++
++NODE_SSTPORT_1= @mysqld.1.#sst_port
++NODE_SSTPORT_2= @mysqld.2.#sst_port
++NODE_SSTPORT_3= @mysqld.3.#sst_port
++
+diff --git a/mysql-test/suite/galera_3nodes/my.cnf b/mysql-test/suite/galera_3nodes/my.cnf
+new file mode 100644
+index 0000000..bb25b95
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/my.cnf
+@@ -0,0 +1 @@
++!include galera_3nodes.cnf
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result b/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result
+new file mode 100644
+index 0000000..96a2bec
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result
+@@ -0,0 +1,17 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 3
++1
++SET GLOBAL wsrep_cluster_address = '';
++INSERT INTO t1 VALUES (2);
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++COMMIT;
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result b/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result
+new file mode 100644
+index 0000000..9dc735d
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result
+@@ -0,0 +1,12 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++COMMIT;
++ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result b/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
+new file mode 100644
+index 0000000..1464222
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
+@@ -0,0 +1,19 @@
++SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
++SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
++Suspending node ...
++SET SESSION wsrep_sync_wait = 0;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++CREATE TABLE t1 (f1 INTEGER);
++INSERT INTO t1 VALUES (1);
++SET SESSION wsrep_sync_wait = 0;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 2
++1
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++DROP TABLE t1;
++Resuming node ...
++CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_garbd.result b/mysql-test/suite/galera_3nodes/r/galera_garbd.result
+new file mode 100644
+index 0000000..616c9d3
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_garbd.result
+@@ -0,0 +1,14 @@
++Killing node #3 to free ports for garbd ...
++Starting garbd ...
++CREATE TABLE t1 (f1 INTEGER);
++INSERT INTO t1 VALUES (1);
++SELECT COUNT(*) = 1 FROM t1;
++COUNT(*) = 1
++1
++Killing garbd ...
++INSERT INTO t1 VALUES (2);
++SELECT COUNT(*) = 2 FROM t1;
++COUNT(*) = 2
++1
++DROP TABLE t1;
++Restarting node #3 to satisfy MTR's end-of-test checks
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result
+new file mode 100644
+index 0000000..1ecea5d
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result
+@@ -0,0 +1,46 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
++INSERT INTO t1 VALUES (01), (02), (03), (04), (05);
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++Unloading wsrep provider ...
++SET GLOBAL wsrep_provider = 'none';
++INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
++INSERT INTO t1 VALUES (21), (22), (23), (24), (25);
++SET GLOBAL wsrep_provider_options = 'dbug=d,ist_sender_send_after_get_buffers';
++INSERT INTO t1 VALUES (31), (32), (33), (34), (35);
++SHOW STATUS LIKE 'wsrep_debug_sync_waiters';
++Variable_name Value
++wsrep_debug_sync_waiters      ist_sender_send_after_get_buffers ist_sender_send_after_get_buffers
++INSERT INTO t1 VALUES (41), (42), (43), (44), (45);
++CREATE TABLE t2 (f1 LONGTEXT);
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++SET GLOBAL wsrep_provider_options = 'signal=ist_sender_send_after_get_buffers';
++SET GLOBAL wsrep_provider_options = 'dbug=';
++INSERT INTO t1 VALUES (51), (52), (53), (54), (55);
++SELECT COUNT(*) = 30 FROM t1;
++COUNT(*) = 30
++1
++SELECT COUNT(*) = 3 FROM t2;
++COUNT(*) = 3
++1
++SELECT LENGTH(f1) = 512 * 1024 FROM t2;
++LENGTH(f1) = 512 * 1024
++1
++1
++1
++CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled");
++SELECT COUNT(*) = 30 FROM t1;
++COUNT(*) = 30
++1
++SELECT COUNT(*) = 3 FROM t2;
++COUNT(*) = 3
++1
++SELECT LENGTH(f1) = 512 * 1024 FROM t2;
++LENGTH(f1) = 512 * 1024
++1
++1
++1
++CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled");
++DROP TABLE t1, t2;
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result
+new file mode 100644
+index 0000000..9a6d40a
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result
+@@ -0,0 +1,13 @@
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++SET GLOBAL wsrep_slave_threads = 2;
++UPDATE t1 SET f1 = f1 + 10;;
++UPDATE t1 SET f1 = f1 + 100;;
++SELECT f1 = 111 FROM t1;
++f1 = 111
++1
++SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
++COUNT(*) IN (1, 2)
++1
++SET GLOBAL wsrep_slave_threads = 1;;
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result b/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
+new file mode 100644
+index 0000000..ca05143
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
+@@ -0,0 +1,118 @@
++SET GLOBAL wsrep_provider_options = 'pc.weight=3';
++Suspending node ...
++SET SESSION wsrep_sync_wait=0;
++SHOW STATUS LIKE 'wsrep_cluster_size';
++Variable_name Value
++wsrep_cluster_size    2
++SHOW STATUS LIKE 'wsrep_cluster_status';
++Variable_name Value
++wsrep_cluster_status  non-Primary
++SHOW STATUS LIKE 'wsrep_connected';
++Variable_name Value
++wsrep_connected       ON
++SHOW STATUS LIKE 'wsrep_ready';
++Variable_name Value
++wsrep_ready   OFF
++SHOW STATUS LIKE 'wsrep_local_state';
++Variable_name Value
++wsrep_local_state     0
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++Variable_name Value
++wsrep_local_state_comment     Initialized
++SET SESSION wsrep_sync_wait=0;
++SHOW STATUS LIKE 'wsrep_cluster_size';
++Variable_name Value
++wsrep_cluster_size    2
++SHOW STATUS LIKE 'wsrep_cluster_status';
++Variable_name Value
++wsrep_cluster_status  non-Primary
++SHOW STATUS LIKE 'wsrep_connected';
++Variable_name Value
++wsrep_connected       ON
++SHOW STATUS LIKE 'wsrep_ready';
++Variable_name Value
++wsrep_ready   OFF
++SHOW STATUS LIKE 'wsrep_local_state';
++Variable_name Value
++wsrep_local_state     0
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++Variable_name Value
++wsrep_local_state_comment     Initialized
++Resuming node ...
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 1
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SET SESSION wsrep_sync_wait=0;
++SET SESSION wsrep_sync_wait=0;
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 3
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 3
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++VARIABLE_VALUE = 3
++1
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++VARIABLE_VALUE = 'Primary'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++VARIABLE_VALUE = 'ON'
++1
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++VARIABLE_VALUE = 4
++1
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++VARIABLE_VALUE = 'Synced'
++1
++CALL mtr.add_suppression('WSREP: gcs_caused\\(\\) returned -1');
++CALL mtr.add_suppression('WSREP: user message in state LEAVING');
++CALL mtr.add_suppression('sending install message failed: Transport endpoint is not connected');
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_certification_ccc.test b/mysql-test/suite/galera_3nodes/t/galera_certification_ccc.test
+new file mode 100644
+index 0000000..da4a609
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_certification_ccc.test
+@@ -0,0 +1,41 @@
++#
++# Test that a cluster configuration change during a transaction does not cause a failure
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++
++--connection node_3
++--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
++SET GLOBAL wsrep_cluster_address = '';
++--sleep 5
++
++--connection node_1
++INSERT INTO t1 VALUES (2);
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++COMMIT;
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++--connection node_3
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++--sleep 5
++--source include/galera_wait_ready.inc
++
++--connection node_1
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test b/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test
+new file mode 100644
+index 0000000..a2ad076
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test
+@@ -0,0 +1,33 @@
++#
++# This test creates a transaction whose certification will fail on two separate nodes
++# for two different reasons.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++
++--connection node_1
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES (1);
++INSERT INTO t2 VALUES (1);
++
++--connection node_2
++INSERT INTO t1 VALUES (1);
++
++--connection node_3
++INSERT INTO t2 VALUES (1);
++
++--connection node_1
++--error ER_LOCK_DEADLOCK
++COMMIT;
++
++DROP TABLE t1;
++DROP TABLE t2;
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test b/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
+new file mode 100644
+index 0000000..a87f19a
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
+@@ -0,0 +1,67 @@
++#
++# Test the operation of evs.suspect_timeout.
++#
++# We set evs.inactive_timeout to a very high value so that evs.suspect_timeout can kick in instead.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--connection node_1
++--let $wsrep_provider_options_node1 = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
++
++--connection node_2
++--source include/wait_until_connected_again.inc
++--let $wsrep_provider_options_node2 = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++--connection node_3
++--source include/wait_until_connected_again.inc
++--let $wsrep_cluster_address_node3 = `SELECT @@wsrep_cluster_address`
++
++# Suspend node #3
++
++--source include/galera_suspend.inc
++--sleep 5
++
++# Confirm that the other nodes have booted it out
++
++--connection node_1
++--source include/wait_until_connected_again.inc
++SET SESSION wsrep_sync_wait = 0;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node1';
++--enable_query_log
++
++--source include/wait_until_connected_again.inc
++CREATE TABLE t1 (f1 INTEGER);
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SET SESSION wsrep_sync_wait = 0;
++SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++--disable_query_log
++--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node2';
++--enable_query_log
++
++--source include/wait_until_connected_again.inc
++SELECT COUNT(*) = 1 FROM t1;
++DROP TABLE t1;
++
++# Reconnect node #3 so that MTR's end-of-test checks can run
++
++--connection node_3
++--source include/galera_resume.inc
++--source include/wait_until_connected_again.inc
++
++CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
++
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node3';
++--enable_query_log
++--source include/wait_until_connected_again.inc
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_garbd.test b/mysql-test/suite/galera_3nodes/t/galera_garbd.test
+new file mode 100644
+index 0000000..3f58783
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_garbd.test
+@@ -0,0 +1,50 @@
++#
++# A very basic test for the galera arbitrator. We shut down node #3 and use its port allocation to start garbd.
++# As MTR does not allow multiple servers to be down at the same time, we are limited as to what we can test.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/big_test.inc
++
++--echo Killing node #3 to free ports for garbd ...
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++--source include/shutdown_mysqld.inc
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++--echo Starting garbd ...
++--exec `dirname $WSREP_PROVIDER`/garb/garbd --address "gcomm://127.0.0.1:$NODE_GALERAPORT_1" --group my_wsrep_cluster --options 'base_port=$NODE_GALERAPORT_3' > $MYSQL_TMP_DIR/garbd.log 2>&1 &
++
++--sleep 5
++
++--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++CREATE TABLE t1 (f1 INTEGER);
++INSERT INTO t1 VALUES (1);
++
++--connection node_2
++SELECT COUNT(*) = 1 FROM t1;
++
++--echo Killing garbd ...
++--exec pkill --oldest --full garbd.*$NODE_GALERAPORT_3
++
++--connection node_1
++--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++INSERT INTO t1 VALUES (2);
++
++--connection node_2
++SELECT COUNT(*) = 2 FROM t1;
++
++DROP TABLE t1;
++
++--echo Restarting node #3 to satisfy MTR's end-of-test checks
++--connection node_3
++--source include/start_mysqld.inc
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.cnf b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.cnf
+new file mode 100644
+index 0000000..8211752
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.cnf
+@@ -0,0 +1,11 @@
++!include ../galera_3nodes.cnf
++
++[mysqld.1]
++wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true;gcache.size=1M'
++
++[mysqld.2]
++wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true;gcache.size=1M'
++
++[mysqld.3]
++wsrep_provider_options='base_port=@mysqld.3.#galera_port;pc.ignore_sb=true;gcache.size=1M'
++
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
+new file mode 100644
+index 0000000..0668c24
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
+@@ -0,0 +1,98 @@
++#
++# Test that if the gcache rolls over while IST is in progress, IST will still complete.
++# This is achieved by using the ist_sender_send_after_get_buffers Galera dbug sync point to block the donor after 
++# the first gcache buffer has been locked for IST.
++#
++# After IST blocks, we roll over the gcache and resume IST to confirm that it completes successfully.
++#
++# Two nodes perform IST at the same time in order to make the test more stressfull
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++--source include/have_debug_sync.inc
++--source suite/galera/include/galera_have_debug_sync.inc
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
++INSERT INTO t1 VALUES (01), (02), (03), (04), (05);
++
++# Disconnect nodes #2 and #3
++--connection node_2
++--source suite/galera/include/galera_unload_provider.inc
++
++--connection node_3
++--source suite/galera/include/galera_unload_provider.inc
++
++--connection node_1
++--source include/wait_until_connected_again.inc
++INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
++
++# Wait until nodes #2 and #3 have left
++--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
++--source include/wait_condition.inc
++
++INSERT INTO t1 VALUES (21), (22), (23), (24), (25);
++
++# Make sure IST will block ...
++SET GLOBAL wsrep_provider_options = 'dbug=d,ist_sender_send_after_get_buffers';
++
++# ... and restart providers to force IST
++--connection node_2
++--disable_query_log
++--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++--connection node_1
++INSERT INTO t1 VALUES (31), (32), (33), (34), (35);
++
++--connection node_3
++--disable_query_log
++--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
++--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
++--enable_query_log
++
++--connection node_1
++--sleep 2
++SHOW STATUS LIKE 'wsrep_debug_sync_waiters';
++
++INSERT INTO t1 VALUES (41), (42), (43), (44), (45);
++
++# Roll over gcache by writing a lot of information to it
++
++CREATE TABLE t2 (f1 LONGTEXT);
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024));
++
++# Unlock IST and wait for it to complete
++SET GLOBAL wsrep_provider_options = 'signal=ist_sender_send_after_get_buffers';
++SET GLOBAL wsrep_provider_options = 'dbug=';
++
++INSERT INTO t1 VALUES (51), (52), (53), (54), (55);
++
++--connection node_2
++--source include/wait_until_connected_again.inc
++
++--connection node_3
++--source include/wait_until_connected_again.inc
++
++# Final checks 
++--connection node_2
++SELECT COUNT(*) = 30 FROM t1;
++SELECT COUNT(*) = 3 FROM t2;
++SELECT LENGTH(f1) = 512 * 1024 FROM t2;
++CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled");
++
++# Final checks
++--connection node_3
++SELECT COUNT(*) = 30 FROM t1;
++SELECT COUNT(*) = 3 FROM t2;
++SELECT LENGTH(f1) = 512 * 1024 FROM t2;
++CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled");
++
++DROP TABLE t1, t2;
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test
+new file mode 100644
+index 0000000..659df2b
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test
+@@ -0,0 +1,38 @@
++#
++# This test performs two dependent updates on two nodes and checks the results on the third where
++# parallel apply is enabled.
++#
++
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++
++CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
++INSERT INTO t1 VALUES (1);
++
++--connection node_3
++--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
++SET GLOBAL wsrep_slave_threads = 2;
++
++--connection node_1
++--send UPDATE t1 SET f1 = f1 + 10;
++
++--connection node_2
++--send UPDATE t1 SET f1 = f1 + 100;
++
++--connection node_1
++--reap
++
++--connection node_2
++--reap
++
++--connection node_3
++SELECT f1 = 111 FROM t1;
++SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
++
++--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
++
++DROP TABLE t1;
+diff --git a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
+new file mode 100644
+index 0000000..8956bae
+--- /dev/null
++++ b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
+@@ -0,0 +1,110 @@
++#
++# Test the pc.weight wsrep provider option. We set Node #1 to have a high weight and then 
++# suspend it. This will cause Nodes #2 and #3 to transition to non-primary component.
++#
++
++--source include/big_test.inc
++--source include/galera_cluster.inc
++--source include/have_innodb.inc
++
++--let $wsrep_provider_options_node1 = `SELECT @@wsrep_provider_options`
++SET GLOBAL wsrep_provider_options = 'pc.weight=3';
++
++--source include/wait_until_connected_again.inc
++--source include/galera_suspend.inc
++--sleep 10
++
++--connection node_2
++# Do not wait for causality as we are no longer in the primary component
++SET SESSION wsrep_sync_wait=0;
++--source include/wait_until_connected_again.inc
++
++# We can not use SELECT queries here, as only SHOW is allowed to run.
++# For nodes #2 and #3, we expect a non-primary component of size 2
++
++SHOW STATUS LIKE 'wsrep_cluster_size';
++SHOW STATUS LIKE 'wsrep_cluster_status';
++SHOW STATUS LIKE 'wsrep_connected';
++SHOW STATUS LIKE 'wsrep_ready';
++SHOW STATUS LIKE 'wsrep_local_state';
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++
++--let $galera_connection_name = node_3
++--let $galera_server_number = 3
++--source include/galera_connect.inc
++--connection node_3
++SET SESSION wsrep_sync_wait=0;
++--source include/wait_until_connected_again.inc
++
++SHOW STATUS LIKE 'wsrep_cluster_size';
++SHOW STATUS LIKE 'wsrep_cluster_status';
++SHOW STATUS LIKE 'wsrep_connected';
++SHOW STATUS LIKE 'wsrep_ready';
++SHOW STATUS LIKE 'wsrep_local_state';
++SHOW STATUS LIKE 'wsrep_local_state_comment';
++
++--connection node_1
++--source include/galera_resume.inc
++--sleep 5
++--source include/wait_until_connected_again.inc
++
++# For Node #1, we expect a primary component of size 1
++
++SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++# Restore the cluster by resetting wsrep_cluster_address on nodes #1 and #2
++
++--connection node_2
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++--enable_query_log
++
++SET SESSION wsrep_sync_wait=0;
++--source include/wait_until_connected_again.inc
++
++--connection node_3
++--disable_query_log
++--eval SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address;
++--enable_query_log
++
++SET SESSION wsrep_sync_wait=0;
++--source include/wait_until_connected_again.inc
++
++# On all nodes, we now expect a Primary component of size 3, Synced and ready
++
++--connection node_1
++--source include/wait_until_connected_again.inc
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++--connection node_2
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++--connection node_3
++SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
++SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
++SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
++SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
++SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
++
++--connection node_1
++CALL mtr.add_suppression('WSREP: gcs_caused\\(\\) returned -1');
++
++--connection node_3
++CALL mtr.add_suppression('WSREP: user message in state LEAVING');
++CALL mtr.add_suppression('sending install message failed: Transport endpoint is not connected');
+diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result
+index 0e0f49b..21acf06 100644
+--- a/mysql-test/suite/innodb/r/innodb-autoinc.result
++++ b/mysql-test/suite/innodb/r/innodb-autoinc.result
+@@ -197,7 +197,7 @@ c1 c2
+ 5     9
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      100
+ auto_increment_offset 10
+@@ -228,9 +228,10 @@ c1
+ 410
+ 1000
+ DROP TABLE t1;
++SET GLOBAL wsrep_auto_increment_control=OFF;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -269,7 +270,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -282,7 +283,7 @@ SELECT * FROM t1;
+ c1
+ -1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      100
+ auto_increment_offset 10
+@@ -315,7 +316,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -330,7 +331,7 @@ SELECT * FROM t1;
+ c1
+ 1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      100
+ auto_increment_offset 10
+@@ -370,7 +371,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -385,7 +386,7 @@ SELECT * FROM t1;
+ c1
+ 1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      100
+ auto_increment_offset 10
+@@ -419,7 +420,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -434,7 +435,7 @@ c1
+ 1
+ 9223372036854775794
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      2
+ auto_increment_offset 10
+@@ -452,7 +453,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -467,7 +468,7 @@ c1
+ 1
+ 18446744073709551603
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      2
+ auto_increment_offset 10
+@@ -480,7 +481,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -495,7 +496,7 @@ c1
+ 1
+ 18446744073709551603
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      5
+ auto_increment_offset 7
+@@ -508,7 +509,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -527,7 +528,7 @@ c1
+ -9223372036854775806
+ 1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      3
+ auto_increment_offset 3
+@@ -544,7 +545,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -562,7 +563,7 @@ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCRE
+ Warnings:
+ Warning       1292    Truncated incorrect auto_increment_increment value: '1152921504606846976'
+ Warning       1292    Truncated incorrect auto_increment_offset value: '1152921504606846976'
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      65535
+ auto_increment_offset 65535
+@@ -575,7 +576,7 @@ c1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -862,7 +863,7 @@ Got one of the listed errors
+ DROP TABLE t1;
+ DROP TABLE t2;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+@@ -1252,7 +1253,7 @@ t1       CREATE TABLE `t1` (
+ ) ENGINE=InnoDB AUTO_INCREMENT=18446744073709551615 DEFAULT CHARSET=latin1
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 256
+@@ -1270,7 +1271,7 @@ c1       c2
+ 1     NULL
+ DROP TABLE t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ Variable_name Value
+ auto_increment_increment      1
+ auto_increment_offset 1
+diff --git a/mysql-test/suite/innodb/t/galera.skip b/mysql-test/suite/innodb/t/galera.skip
+new file mode 100644
+index 0000000..54e07b4
+--- /dev/null
++++ b/mysql-test/suite/innodb/t/galera.skip
+@@ -0,0 +1,43 @@
++innodb : deadlock, failure in UPDATE IGNORE, lp1372296
++innodb_ctype_ldml : Test contains statements unsafe to replicate in statement-based replication
++innodb-autoinc : deadlock, failure in REPLACE, lp1372296
++innodb_mysql : deadlock due to DDL
++innodb_buffer_pool_load : Test contains statements unsafe to replicate in statement-based replication
++innodb-autoinc-56228 : deadlock, lp1372301
++innodb_lock_wait_timeout_1 : Test contains statements unsafe to replicate in statement-based replication
++innodb-consistent : Test contains statements unsafe to replicate in statement-based replication
++innodb-semi-consistent : Test contains statements unsafe to replicate in statement-based replication
++innodb-index : DDL concurrent with transaction
++innodb-lock : deadlock on INSERT IGNORE, lp1372296
++innodb-status-output : Test performs server restart
++innodb-wl5522 : Test contains statements unsafe to replicate in statement-based replication
++innodb-wl6445 : Test performs server restart
++innodb_bug40360 : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug40565 : Galera git bug #137 - Invalid deadlock on UPDATE to NULL without a PK
++innodb_bug42419 : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug49164 : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug45357 : impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging
++innodb_bug52663 : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug59733 : Test contains statements unsafe to replicate in statement-based replication
++innodb_gis : Test contains statements unsafe to replicate in statement-based replication
++innodb_prefix_index_restart_server : crash, lp1372288
++innodb_stats_external_pages : Test contains statements unsafe to replicate in statement-based replication
++innodb-2byte-collation : Unsafe statement written to the binary log
++innodb-change-buffer-recovery : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug53756 : Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT
++innodb-alter-autoinc : AUTO_INCREMENT differences
++innodb_bug13635833 : Test contains statements unsafe to replicate in statement-based replication
++innodb_bug13867871 : mysql-wsrep#3 - innodb_bug13867871 test fails with wsrep loaded
++innodb_bug14006907 : DDL lock wait timeout
++innodb_bug38231 : Deadlock on UNLOCK TABLE
++innodb_bug-13628249 : mysql-wsrep#12 InnoDB: Failing assertion: !srv_read_only_mode with server restart 
++innodb-wl6445-1 : mysql-wsrep#12 InnoDB: Failing assertion: !srv_read_only_mode with server restart
++innodb-wl6445-2 : mysql-wsrep#12 InnoDB: Failing assertion: !srv_read_only_mode with server restart
++innodb_bug12400341 : Test does not account for applier threads when performing SHOW PROCESSLIST
++innodb-blob : 'Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging'
++innodb_corrupt_bit : 'Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'
++innodb-index-online : ALTER succeeds as it is given a higher priority
++innodb-table-online : ALTER succeeds as it is given a higher priority
++innodb-index-online-purge : ALTER succeeds as it is given a higher priority
++innodb-wl5522-debug : Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
++innodb_stats_table_flag_auto_recalc : Performs multiple restarts in a row which causes '1047: Unknown command' errors
+diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test
+index 3d9f591..7cc8065 100644
+--- a/mysql-test/suite/innodb/t/innodb-autoinc.test
++++ b/mysql-test/suite/innodb/t/innodb-autoinc.test
+@@ -156,7 +156,7 @@ DROP TABLE t1;
+ #
+ # Test changes to AUTOINC next value calculation
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES (NULL),(5),(NULL);
+@@ -171,9 +171,11 @@ DROP TABLE t1;
+ # Test with SIGNED INT column, by inserting a 0 for the first column value
+ # 0 is treated in the same was NULL.
+ # Reset the AUTOINC session variables
++SET GLOBAL wsrep_auto_increment_control=OFF;
++
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES(0);
+@@ -193,13 +195,13 @@ DROP TABLE t1;
+ # Reset the AUTOINC session variables
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES(-1);
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL);
+ INSERT INTO t1 VALUES (250),(NULL);
+ SELECT * FROM t1;
+@@ -214,13 +216,13 @@ DROP TABLE t1;
+ # Reset the AUTOINC session variables
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES(-1);
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ INSERT INTO t1 VALUES (-2);
+ INSERT INTO t1 VALUES (NULL);
+ INSERT INTO t1 VALUES (2);
+@@ -240,13 +242,13 @@ DROP TABLE t1;
+ # Reset the AUTOINC session variables
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES(-1);
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL);
+ INSERT INTO t1 VALUES (250),(NULL);
+ SELECT * FROM t1;
+@@ -262,7 +264,7 @@ DROP TABLE t1;
+ # Check for overflow handling when increment is > 1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ # TODO: Fix the autoinc init code
+@@ -271,7 +273,7 @@ INSERT INTO t1 VALUES(NULL);
+ INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ # This should just fit
+ INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
+ SELECT * FROM t1;
+@@ -281,7 +283,7 @@ DROP TABLE t1;
+ # Check for overflow handling when increment and offser are > 1
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ # TODO: Fix the autoinc init code
+@@ -290,7 +292,7 @@ INSERT INTO t1 VALUES(NULL);
+ INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ --error ER_AUTOINC_READ_FAILED
+ INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
+ SELECT * FROM t1;
+@@ -300,7 +302,7 @@ DROP TABLE t1;
+ # Check for overflow handling when increment and offset are odd numbers
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ # TODO: Fix the autoinc init code
+@@ -309,7 +311,7 @@ INSERT INTO t1 VALUES(NULL);
+ INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ --error ER_AUTOINC_READ_FAILED
+ INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
+ SELECT * FROM t1;
+@@ -319,7 +321,7 @@ DROP TABLE t1;
+ # and check for large -ve numbers
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ # TODO: Fix the autoinc init code
+@@ -330,7 +332,7 @@ INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1
+ INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
+ SELECT * FROM t1;
+ DROP TABLE t1;
+@@ -339,7 +341,7 @@ DROP TABLE t1;
+ # large numbers 2^60
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
+ # TODO: Fix the autoinc init code
+@@ -348,7 +350,7 @@ INSERT INTO t1 VALUES(NULL);
+ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2
+ SELECT * FROM t1;
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ --error ER_WARN_DATA_OUT_OF_RANGE
+ INSERT INTO t1 VALUES (NULL),(NULL);
+ SELECT * FROM t1;
+@@ -359,7 +361,7 @@ DROP TABLE t1;
+ #
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+ SET @@INSERT_ID=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES(NULL, 1);
+ INSERT INTO t1 VALUES(NULL, 2);
+@@ -445,7 +447,7 @@ DROP TABLE t2;
+ # If the user has specified negative values for an AUTOINC column then
+ # InnoDB should ignore those values when setting the table's max value.
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ # TINYINT
+ CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES (1, NULL);
+@@ -641,7 +643,7 @@ DROP TABLE t1;
+ # Check if we handle offset > column max value properly
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ # TINYINT
+ CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES (1, NULL);
+@@ -653,7 +655,7 @@ DROP TABLE t1;
+ # of the column. IMO, this should not be allowed and the assertion that fails
+ # is actually an invariant.
+ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
+-SHOW VARIABLES LIKE "%auto_inc%";
++SHOW VARIABLES LIKE "auto_inc%";
+ # TINYINT
+ CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+ INSERT INTO t1 VALUES (2147483648, 'a');
+diff --git a/mysql-test/suite/opt_trace/t/disabled.def b/mysql-test/suite/opt_trace/t/disabled.def
+new file mode 100644
+index 0000000..3ed40b8
+--- /dev/null
++++ b/mysql-test/suite/opt_trace/t/disabled.def
+@@ -0,0 +1,2 @@
++general_no_prot_all : Galera mysql-wsrep#5 2014-10-28 pstoev opt_trace.general_no_prot_none and opt_trace.general_no_prot_all fail in mysql-wsrep
++general_no_prot_none : Galera mysql-wsrep#5 2014-10-28 pstoev opt_trace.general_no_prot_none and opt_trace.general_no_prot_all fail in mysql-wsrep
+diff --git a/mysql-test/suite/parts/r/partition_exch_qa_10.result b/mysql-test/suite/parts/r/partition_exch_qa_10.result
+index 77b91f1..7193a6c 100644
+--- a/mysql-test/suite/parts/r/partition_exch_qa_10.result
++++ b/mysql-test/suite/parts/r/partition_exch_qa_10.result
+@@ -23,7 +23,7 @@ a    b
+ DROP PROCEDURE test_p1;
+ SET @save_autocommit= @@autocommit;
+ SET @@autocommit= OFF;
+-SHOW VARIABLES LIKE '%autocommit%';
++SHOW VARIABLES LIKE 'autocommit%';
+ Variable_name Value
+ autocommit    OFF
+ CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW
+diff --git a/mysql-test/suite/parts/t/partition_exch_qa_10.test b/mysql-test/suite/parts/t/partition_exch_qa_10.test
+index 4f56960..a87d658 100644
+--- a/mysql-test/suite/parts/t/partition_exch_qa_10.test
++++ b/mysql-test/suite/parts/t/partition_exch_qa_10.test
+@@ -37,7 +37,7 @@ DROP PROCEDURE test_p1;
+ SET @save_autocommit= @@autocommit;
+ SET @@autocommit= OFF;
+-SHOW VARIABLES LIKE '%autocommit%';
++SHOW VARIABLES LIKE 'autocommit%';
+ DELIMITER |;
+ --error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
+ CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW
+diff --git a/mysql-test/suite/perfschema/r/dml_setup_instruments.result b/mysql-test/suite/perfschema/r/dml_setup_instruments.result
+index b3de51e..5152d9f 100644
+--- a/mysql-test/suite/perfschema/r/dml_setup_instruments.result
++++ b/mysql-test/suite/perfschema/r/dml_setup_instruments.result
+@@ -34,6 +34,7 @@ where name like 'Wait/Synch/Cond/sql/%'
+   and name not in (
+ 'wait/synch/cond/sql/COND_handler_count',
+ 'wait/synch/cond/sql/DEBUG_SYNC::cond')
++and name not like 'wait/synch/cond/sql/COND_wsrep_%'
+ order by name limit 10;
+ NAME  ENABLED TIMED
+ wait/synch/cond/sql/COND_flush_thread_cache   YES     YES
+diff --git a/mysql-test/suite/perfschema/r/rpl_statements.result b/mysql-test/suite/perfschema/r/rpl_statements.result
+index dd8d349..96016bd 100644
+--- a/mysql-test/suite/perfschema/r/rpl_statements.result
++++ b/mysql-test/suite/perfschema/r/rpl_statements.result
+@@ -14,7 +14,7 @@ Note ####    Storing MySQL user name or password information in the master info rep
+ *** Create test tables
+-show variables like '%binlog_format%';
++show variables like 'binlog_format%';
+ Variable_name Value
+ binlog_format MIXED
+ drop table if exists test.marker;
+@@ -58,7 +58,7 @@ Expect 1
+ *** MASTER ***
+ **************
+-show variables like '%binlog_format%';
++show variables like 'binlog_format%';
+ Variable_name Value
+ binlog_format MIXED
+ *** Clear statement events
+diff --git a/mysql-test/suite/perfschema/t/disabled.def b/mysql-test/suite/perfschema/t/disabled.def
+index 888298b..1a6d6b5 100644
+--- a/mysql-test/suite/perfschema/t/disabled.def
++++ b/mysql-test/suite/perfschema/t/disabled.def
+@@ -9,3 +9,6 @@
+ #  Do not use any TAB characters for whitespace.
+ #
+ ##############################################################################
++
++perfschema.sizing_growth : Galera LP#1370988 2014-10-28 pstoev Performance schema heuristics need to be updated
++ortho_iter : Galera mysql-wsrep#34 2014-12-19 perfschema.ortho_iter MTR test fails sporadically
+diff --git a/mysql-test/suite/perfschema/t/dml_setup_instruments.test b/mysql-test/suite/perfschema/t/dml_setup_instruments.test
+index 8a4f11b..b679b7a 100644
+--- a/mysql-test/suite/perfschema/t/dml_setup_instruments.test
++++ b/mysql-test/suite/perfschema/t/dml_setup_instruments.test
+@@ -36,7 +36,8 @@ select * from performance_schema.setup_instruments
+   and name not in (
+     'wait/synch/cond/sql/COND_handler_count',
+     'wait/synch/cond/sql/DEBUG_SYNC::cond')
+-  order by name limit 10;
++  and name not like 'wait/synch/cond/sql/COND_wsrep_%'
++order by name limit 10;
+ --disable_result_log
+ select * from performance_schema.setup_instruments
+diff --git a/mysql-test/suite/perfschema/t/rpl_statements.test b/mysql-test/suite/perfschema/t/rpl_statements.test
+index 8e71961..ac4ece5 100644
+--- a/mysql-test/suite/perfschema/t/rpl_statements.test
++++ b/mysql-test/suite/perfschema/t/rpl_statements.test
+@@ -63,7 +63,7 @@ connection master;
+ --echo *** Create test tables
+ --echo
+-show variables like '%binlog_format%';
++show variables like 'binlog_format%';
+ --disable_warnings
+ drop table if exists test.marker;
+@@ -128,7 +128,7 @@ connection master;
+ --echo *** MASTER ***
+ --echo **************
+ --echo
+-show variables like '%binlog_format%';
++show variables like 'binlog_format%';
+ --echo *** Clear statement events
+ --source ../include/rpl_statements_truncate.inc
+diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment.result b/mysql-test/suite/rpl/r/rpl_auto_increment.result
+index 0d858cf..283d244 100644
+--- a/mysql-test/suite/rpl/r/rpl_auto_increment.result
++++ b/mysql-test/suite/rpl/r/rpl_auto_increment.result
+@@ -42,6 +42,7 @@ show variables like "%auto_inc%";
+ Variable_name Value
+ auto_increment_increment      100
+ auto_increment_offset 10
++wsrep_auto_increment_control  ON
+ create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+ insert into t1 values (NULL),(5),(NULL);
+ insert into t1 values (250),(NULL);
+diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def
+index a82c31c..fd07c96 100644
+--- a/mysql-test/suite/rpl/t/disabled.def
++++ b/mysql-test/suite/rpl/t/disabled.def
+@@ -13,3 +13,4 @@
+ rpl_row_create_table      : Bug#11759274 2010-02-27 andrei failed different way than earlier with bug#45576
+ rpl_delayed_slave         : Bug#11764654 2010-11-09 andrei rpl_delayed_slave fails sporadically in pb
+ rpl_row_binlog_max_cache_size : BUG#14126780 May 29 2012 Vasil Dimov timeout if est number of rows is 3 instead of 4
++rpl_test_framework        : Too many servers started, so fails under Galera-enabled MTR
+diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result
+index e042384..4edc039 100644
+--- a/mysql-test/suite/sys_vars/r/all_vars.result
++++ b/mysql-test/suite/sys_vars/r/all_vars.result
+@@ -1,8 +1,8 @@
+ create table t1 (test_name text);
+ create table t2 (variable_name text);
+ load data infile "MYSQLTEST_VARDIR/tmp/sys_vars.all_vars.txt" into table t1;
+-insert into t2 select variable_name from information_schema.global_variables;
+-insert into t2 select variable_name from information_schema.session_variables;
++insert into t2 select variable_name from information_schema.global_variables where variable_name not like 'wsrep_%' and variable_name not like 'innodb_disallow_writes';
++insert into t2 select variable_name from information_schema.session_variables where variable_name not like 'wsrep_%' and variable_name not like 'innodb_disallow_writes';
+ update t2 set variable_name= replace(variable_name, "PERFORMANCE_SCHEMA_", "PFS_");
+ update t2 set variable_name= replace(variable_name, "_HISTORY_LONG_", "_HL_");
+ update t2 set variable_name= replace(variable_name, "_HISTORY_", "_H_");
+diff --git a/mysql-test/suite/sys_vars/t/all_vars.test b/mysql-test/suite/sys_vars/t/all_vars.test
+index c272528..90f977e 100644
+--- a/mysql-test/suite/sys_vars/t/all_vars.test
++++ b/mysql-test/suite/sys_vars/t/all_vars.test
+@@ -49,8 +49,8 @@ create table t2 (variable_name text);
+ --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+ eval load data infile "$MYSQLTEST_VARDIR/tmp/sys_vars.all_vars.txt" into table t1;
+-insert into t2 select variable_name from information_schema.global_variables;
+-insert into t2 select variable_name from information_schema.session_variables;
++insert into t2 select variable_name from information_schema.global_variables where variable_name not like 'wsrep_%' and variable_name not like 'innodb_disallow_writes';
++insert into t2 select variable_name from information_schema.session_variables where variable_name not like 'wsrep_%' and variable_name not like 'innodb_disallow_writes';
+ # Performance schema variables are too long for files named
+ # 'mysql-test/suite/sys_vars/t/' ...
+diff --git a/mysql-test/suite/wsrep/my.cnf b/mysql-test/suite/wsrep/my.cnf
+new file mode 100644
+index 0000000..81e22a5
+--- /dev/null
++++ b/mysql-test/suite/wsrep/my.cnf
+@@ -0,0 +1,12 @@
++# Use default setting for mysqld processes
++!include include/default_mysqld.cnf
++
++[mysqld.1]
++wsrep_provider=@ENV.WSREP_PROVIDER
++wsrep_cluster_address='gcomm://'
++wsrep_node_address=127.0.0.1
++binlog-format=row
++
++[ENV]
++GALERA_BASE_PORT=@mysqld.1.#galera_port
++
+diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
+index dd8a6f4..ae0eb82 100644
+--- a/mysql-test/t/disabled.def
++++ b/mysql-test/t/disabled.def
+@@ -18,3 +18,4 @@ ds_mrr-big @solaris      : Bug#14168107 2012-04-03 Hemant disabled new test adde
+ mysql_embedded_client_test    : Bug#13964673 2012-04-16 amitbha since most of the test cases are failing
+ mysql_client_test_embedded : Bug#16084066 2013-01-08 Disabled since this test is failing
+ file_contents            : Fails without bzr revision id
++bootstrap : Galera mysql-wsrep#19 2014-11-21 pstoev Crash in LOGGER::error_log_print when printing a WSREP message 
+diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test
+index 2b92d9e..8c0c56f 100644
+--- a/mysql-test/t/mysqltest.test
++++ b/mysql-test/t/mysqltest.test
+@@ -708,7 +708,7 @@ remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
+ # Too many errorcodes specified
+ --error 1
+---exec echo "--error 1,2,3,4,5,6,7,8,9,10,11" | $MYSQL_TEST 2>&1
++--exec echo "--error 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21" | $MYSQL_TEST 2>&1
+ # ----------------------------------------------------------------------------
+diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
+index 9ef8632..9098cd8 100644
+--- a/mysys/thr_lock.c
++++ b/mysys/thr_lock.c
+@@ -82,7 +82,24 @@ one TL_WRITE_DELAYED lock at the same time as multiple read locks.
+ my_bool thr_lock_inited=0;
+ ulong locks_immediate = 0L, locks_waited = 0L;
+ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
+-
++#ifdef WITH_WSREP
++static wsrep_thd_is_brute_force_fun wsrep_thd_is_brute_force= NULL;
++static wsrep_abort_thd_fun wsrep_abort_thd= NULL;
++static my_bool wsrep_debug;
++static my_bool wsrep_convert_LOCK_to_trx;
++static wsrep_on_fun wsrep_on = NULL;
++
++void wsrep_thr_lock_init(
++    wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun,
++    my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun
++) {
++  wsrep_thd_is_brute_force = bf_fun;
++  wsrep_abort_thd          = abort_fun;
++  wsrep_debug              = debug;
++  wsrep_convert_LOCK_to_trx= convert_LOCK_to_trx;
++  wsrep_on                 = on_fun;
++}
++#endif
+ /* The following constants are only for debug output */
+ #define MAX_THREADS 100
+ #define MAX_LOCKS   100
+@@ -536,6 +553,108 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
+   DBUG_RETURN(result);
+ }
++#ifdef WITH_WSREP
++/*
++ * If brute force applier would need to wait for a thr lock,
++ * it needs to make sure that it will get the lock without (too much) 
++ * delay. 
++ * We identify here the owners of blocking locks and ask them to
++ * abort. We then put our lock request in the first place in the
++ * wait queue. When lock holders abort (one by one) the lock release
++ * algorithm should grant the lock to us. We rely on this and proceed
++ * to wait_for_locks().
++ * wsrep_break_locks() should be called in all the cases, where lock
++ * wait would happen.
++ *
++ * TODO: current implementation might not cover all possible lock wait
++ *       situations. This needs an review still.
++ * TODO: lock release, might favor some other lock (instead our bf).
++ *       This needs an condition to check for bf locks first.
++ * TODO: we still have a debug fprintf, this should be removed
++ */
++static inline my_bool 
++wsrep_break_lock(
++    THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, 
++    struct st_lock_list *lock_queue2, struct st_lock_list *wait_queue)
++{
++  if (wsrep_on(data->owner->mysql_thd) &&
++      wsrep_thd_is_brute_force          &&
++      wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE))
++  {
++    THR_LOCK_DATA *holder;
++
++    /* if locking session conversion to transaction has been enabled,
++       we know that this conflicting lock must be read lock and furthermore,
++       lock holder is read-only. It is safe to wait for him.
++    */
++#ifdef TODO
++    if (wsrep_convert_LOCK_to_trx && 
++      (THD*)(data->owner->mysql_thd)->in_lock_tables)
++    {
++      if (wsrep_debug) 
++        fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n");
++      return FALSE;
++    }
++#endif
++    if (wsrep_debug) 
++      fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n");
++
++    /* aborting lock holder(s) here */
++    for (holder=(lock_queue1) ? lock_queue1->data : NULL; 
++       holder; 
++       holder=holder->next) 
++    {
++      if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE))
++      {
++        wsrep_abort_thd(data->owner->mysql_thd, 
++                        holder->owner->mysql_thd, FALSE);
++      }
++      else
++      {
++        if (wsrep_debug) 
++          fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n");
++         return FALSE;
++      }
++    }
++    for (holder=(lock_queue2) ? lock_queue2->data :  NULL; 
++       holder; 
++       holder=holder->next) 
++    {
++      if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE))
++      {
++        wsrep_abort_thd(data->owner->mysql_thd,
++                        holder->owner->mysql_thd, FALSE);
++      }
++      else
++      {
++        if (wsrep_debug) 
++          fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n");
++         return FALSE;
++      }
++    }
++        
++    /* Add our lock to the head of the wait queue */
++    if (*(wait_queue->last)==wait_queue->data)
++    {
++      wait_queue->last=&data->next;
++      assert(wait_queue->data==0);
++    }
++    else
++    {
++      assert(wait_queue->data!=0);
++      wait_queue->data->prev=&data->next;
++    }
++    data->next=wait_queue->data;
++    data->prev=&wait_queue->data;
++    wait_queue->data=data;
++    data->cond=get_cond();
++
++    statistic_increment(locks_immediate,&THR_LOCK_lock);
++    return TRUE;
++  }
++  return FALSE;
++}
++#endif
+ enum enum_thr_lock_result
+ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+@@ -544,6 +663,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+   THR_LOCK *lock=data->lock;
+   enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
+   struct st_lock_list *wait_queue;
++#ifdef WITH_WSREP
++  my_bool wsrep_lock_inserted= FALSE;
++#endif
+   MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */
+   DBUG_ENTER("thr_lock");
+@@ -613,6 +735,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+       }
+       if (lock->write.data->type == TL_WRITE_ONLY)
+       {
++#ifdef WITH_WSREP
++        if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait))
++        {
++          wsrep_lock_inserted= TRUE;
++          goto wsrep_read_wait;
++        }
++#endif
+       /* We are not allowed to get a READ lock in this case */
+       data->type=TL_UNLOCK;
+         result= THR_LOCK_ABORTED;               /* Can't wait for this one */
+@@ -640,6 +769,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+       lock but a high priority write waiting in the write_wait queue.
+       In the latter case we should yield the lock to the writer.
+     */
++#ifdef WITH_WSREP
++    if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait))
++    {
++      wsrep_lock_inserted= TRUE;
++    }
++  wsrep_read_wait:
++#endif
+     wait_queue= &lock->read_wait;
+   }
+   else                                                /* Request for WRITE lock */
+@@ -648,12 +784,25 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+     {
+       if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
+       {
++#ifdef WITH_WSREP
++        if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait))
++        {
++          wsrep_lock_inserted=TRUE;
++            goto wsrep_write_wait;
++        }
++#endif
+       data->type=TL_UNLOCK;
+         result= THR_LOCK_ABORTED;               /* Can't wait for this one */
+       goto end;
+       }
+       if (lock->write.data || lock->read.data)
+       {
++#ifdef WITH_WSREP
++        if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait))
++        {
++          goto end;
++        }
++#endif
+       /* Add delayed write lock to write_wait queue, and return at once */
+       (*lock->write_wait.last)=data;
+       data->prev=lock->write_wait.last;
+@@ -678,6 +827,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+         /* Allow lock owner to bypass TL_WRITE_ONLY. */
+         if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
+         {
++#ifdef WITH_WSREP
++          if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait))
++          {
++            wsrep_lock_inserted=TRUE;
++            goto wsrep_write_wait;
++          }
++#endif
+           /* We are not allowed to get a lock in this case */
+           data->type=TL_UNLOCK;
+           result= THR_LOCK_ABORTED;               /* Can't wait for this one */
+@@ -781,9 +937,20 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
+       DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
+                        lock->read.data->owner->thread_id, data->type));
+     }
++#ifdef WITH_WSREP
++    if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait))
++    {
++      wsrep_lock_inserted= TRUE;
++    }
++  wsrep_write_wait:
++#endif
+     wait_queue= &lock->write_wait;
+   }
+   /* Can't get lock yet;  Wait for it */
++#ifdef WITH_WSREP
++  if (wsrep_on(data->owner->mysql_thd) && wsrep_lock_inserted)
++    DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout));
++#endif
+   result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout);
+   MYSQL_END_TABLE_LOCK_WAIT(locker);
+   DBUG_RETURN(result);
+diff --git a/mysys_ssl/my_default.cc b/mysys_ssl/my_default.cc
+index 6712b79..ff8f44c 100644
+--- a/mysys_ssl/my_default.cc
++++ b/mysys_ssl/my_default.cc
+@@ -110,6 +110,12 @@ static char my_login_file[FN_REFLEN];
+ static my_bool defaults_already_read= FALSE;
++#ifdef WITH_WSREP
++/* The only purpose of this global array is to hold full name of my.cnf
++ * which seems to be otherwise unavailable */
++char wsrep_defaults_file[FN_REFLEN + 10]={0,};
++char wsrep_defaults_group_suffix[FN_EXTLEN]={0,};
++#endif /* WITH_WREP */
+ /* Set to TRUE, if --no-defaults is found. */
+ static my_bool found_no_defaults= FALSE;
+@@ -534,6 +540,13 @@ int get_defaults_options(int argc, char **argv,
+     if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
+     {
+       *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
++
++#ifdef WITH_WSREP
++      /* make sure we do this only once - for top-level file */
++      if ('\0' == wsrep_defaults_group_suffix[0])
++        strncpy(wsrep_defaults_group_suffix, *group_suffix, sizeof(wsrep_defaults_group_suffix) - 1);
++#endif /* WITH_WSREP */
++
+       argc--;
+       default_option_count ++;
+       continue;
+@@ -893,6 +906,11 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
+     if ( !(fp = mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
+       return 1;                                 /* Ignore wrong files */
+   }
++#ifdef WITH_WSREP
++  /* make sure we do this only once - for top-level file */
++  if ('\0' == wsrep_defaults_file[0])
++    strncpy(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1);
++#endif /* WITH_WSREP */
+   while (mysql_file_getline(buff, sizeof(buff) - 1, fp))
+   {
+diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc
+index 4c14366..1ef0b42 100644
+--- a/mysys_ssl/my_md5.cc
++++ b/mysys_ssl/my_md5.cc
+@@ -66,3 +66,34 @@ void compute_md5_hash(char *digest, const char *buf, int len)
+   my_md5_hash((unsigned char*)digest, (unsigned const char*)buf, len);
+ #endif /* HAVE_YASSL */
+ }
++#ifdef WITH_WSREP
++void *wsrep_md5_init()
++{
++#if defined(HAVE_YASSL)
++  TaoCrypt::MD5 *hasher= new TaoCrypt::MD5;
++  return (void*)hasher;
++#elif defined(HAVE_OPENSSL)
++  MD5_CTX *ctx = new MD5_CTX();
++  MD5_Init (ctx);
++  return (void *)ctx;
++#endif /* HAVE_YASSL */
++}
++void wsrep_md5_update(void *ctx, char* buf, int len)
++{
++#if defined(HAVE_YASSL)
++  ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len);
++#elif defined(HAVE_OPENSSL)
++  MD5_Update((MD5_CTX*)(ctx), buf, len);
++#endif /* HAVE_YASSL */
++}
++void wsrep_compute_md5_hash(char *digest, void *ctx)
++{
++#if defined(HAVE_YASSL)
++  ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest);
++  delete (TaoCrypt::MD5*)ctx;
++#elif defined(HAVE_OPENSSL)
++  MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx);
++  delete (MD5_CTX*)ctx;
++#endif /* HAVE_YASSL */
++}
++#endif
+diff --git a/plugin/innodb_memcached/daemon_memcached/CMakeLists.txt b/plugin/innodb_memcached/daemon_memcached/CMakeLists.txt
+index 11a1276..e53980b 100644
+--- a/plugin/innodb_memcached/daemon_memcached/CMakeLists.txt
++++ b/plugin/innodb_memcached/daemon_memcached/CMakeLists.txt
+@@ -78,7 +78,7 @@ SET(MEMCACHED_SOURCES
+ MYSQL_ADD_PLUGIN(libmemcached ${MEMCACHED_SOURCES}
+               MODULE_ONLY MODULE_OUTPUT_NAME "libmemcached")
+-TARGET_LINK_LIBRARIES(libmemcached ${LIBEVENT_LIBRARY})
++TARGET_LINK_LIBRARIES(libmemcached ${LIBEVENT_LIBRARY} ${LIBEVENT_LIBRARIES})
+ TARGET_LINK_LIBRARIES(libmemcached memcached_utilities)
+ IF(ENABLE_MEMCACHED_SASL)
+diff --git a/plugin/innodb_memcached/innodb_memcache/src/innodb_api.c b/plugin/innodb_memcached/innodb_memcache/src/innodb_api.c
+index 14e2fa7..e062343 100644
+--- a/plugin/innodb_memcached/innodb_memcache/src/innodb_api.c
++++ b/plugin/innodb_memcached/innodb_memcache/src/innodb_api.c
+@@ -666,7 +666,6 @@ innodb_api_copy_mci(
+               } else {
+                       mci_item->value_str = malloc(data_len);
+-
+                       if (!mci_item->value_str) {
+                               return(false);
+                       }
+diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
+index c043f07..a69d938 100644
+--- a/scripts/CMakeLists.txt
++++ b/scripts/CMakeLists.txt
+@@ -320,6 +320,15 @@ IF(WIN32)
+     INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/${file}.pl COMPONENT Server_Scripts)
+   ENDFOREACH()
+ ELSE()
++  IF(WITH_WSREP)
++    SET(WSREP_BINARIES
++      wsrep_sst_common
++      wsrep_sst_mysqldump
++      wsrep_sst_rsync
++      wsrep_sst_xtrabackup
++      wsrep_sst_xtrabackup-v2
++    )
++  ENDIF()
+   # Configure this one, for testing, but do not install it.
+   CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.pl.in
+     ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.pl ESCAPE_QUOTES @ONLY)
+@@ -339,6 +348,7 @@ ELSE()
+     mysqldumpslow
+     mysqld_multi
+     mysqld_safe
++    ${WSREP_BINARIES}
+   )
+   FOREACH(file ${BIN_SCRIPTS})
+     IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh)
+diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh
+index 3b588ef..4520503 100644
+--- a/scripts/mysqld_safe.sh
++++ b/scripts/mysqld_safe.sh
+@@ -141,7 +141,7 @@ log_notice () {
+ }
+ eval_log_error () {
+-  cmd="$1"
++  local cmd="$1"
+   case $logging in
+     file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;;
+     syslog)
+@@ -169,6 +169,78 @@ shell_quote_string() {
+   echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g'
+ }
++wsrep_pick_url() {
++  [ $# -eq 0 ] && return 0
++
++  log_error "WSREP: 'wsrep_urls' is DEPRECATED! Use wsrep_cluster_address to specify multiple addresses instead."
++
++  if ! which nc >/dev/null; then
++    log_error "ERROR: nc tool not found in PATH! Make sure you have it installed."
++    return 1
++  fi
++
++  local url
++  # Assuming URL in the form scheme://host:port
++  # If host and port are not NULL, the liveness of URL is assumed to be tested
++  # If port part is absent, the url is returned literally and unconditionally
++  # If every URL has port but none is reachable, nothing is returned
++  for url in `echo $@ | sed s/,/\ /g` 0; do
++    local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///`
++    local port=`echo $url | cut -d \: -f 3`
++    [ -z "$port" ] && break
++    nc -z "$host" $port >/dev/null && break
++  done
++
++  if [ "$url" == "0" ]; then
++    log_error "ERROR: none of the URLs in '$@' is reachable."
++    return 1
++  fi
++
++  echo $url
++}
++
++# Run mysqld with --wsrep-recover and parse recovered position from log.
++# Position will be stored in wsrep_start_position_opt global.
++wsrep_start_position_opt=""
++wsrep_recover_position() {
++  local mysqld_cmd="$@"
++  local euid=$(id -u)
++  local ret=0
++
++  local wr_logfile=$(mktemp $DATADIR/wsrep_recovery.XXXXXX)
++
++  [ "$euid" = "0" ] && chown $user $wr_logfile
++  chmod 600 $wr_logfile
++
++  local wr_pidfile="$DATADIR/"`@HOSTNAME@`"-recover.pid"
++
++  local wr_options="--log_error='$wr_logfile' --pid-file='$wr_pidfile'"
++
++  log_notice "WSREP: Running position recovery with $wr_options"
++
++  eval_log_error "$mysqld_cmd --wsrep_recover $wr_options"
++
++  local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)"
++  if [ -z "$rp" ]; then
++    local skipped="$(grep WSREP $wr_logfile | grep 'skipping position recovery')"
++    if [ -z "$skipped" ]; then
++      log_error "WSREP: Failed to recover position: " `cat $wr_logfile`;
++      ret=1
++    else
++      log_notice "WSREP: Position recovery skipped"
++    fi
++  else
++    local start_pos="$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \
++        | sed 's/^[ \t]*//')"
++    log_notice "WSREP: Recovered position $start_pos"
++    wsrep_start_position_opt="--wsrep_start_position=$start_pos"
++  fi
++
++  rm $wr_logfile
++
++  return $ret
++}
++
+ parse_arguments() {
+   # We only need to pass arguments through to the server if we don't
+   # handle them here.  So, we collect unrecognized options (passed on
+@@ -224,7 +296,13 @@ parse_arguments() {
+       --skip-syslog) want_syslog=0 ;;
+       --syslog-tag=*) syslog_tag="$val" ;;
+       --timezone=*) TZ="$val"; export TZ; ;;
+-
++      --wsrep[-_]urls=*) wsrep_urls="$val"; ;;
++      --wsrep[-_]provider=*)
++        if test -n "$val" && test "$val" != "none"
++        then
++          wsrep_restart=1
++        fi
++        ;;
+       --help) usage ;;
+       *)
+@@ -770,7 +848,8 @@ do
+ done
+ cmd="$cmd $args"
+ # Avoid 'nohup: ignoring input' warning
+-test -n "$NOHUP_NICENESS" && cmd="$cmd < /dev/null"
++nohup_redir=""
++test -n "$NOHUP_NICENESS" && nohup_redir=" < /dev/null"
+ log_notice "Starting $MYSQLD daemon with databases from $DATADIR"
+@@ -781,13 +860,28 @@ max_fast_restarts=5
+ # flag whether a usable sleep command exists
+ have_sleep=1
++# maximum number of wsrep restarts
++max_wsrep_restarts=0
++
+ while true
+ do
+   rm -f $safe_mysql_unix_port "$pid_file"     # Some extra safety
+   start_time=`date +%M%S`
+-  eval_log_error "$cmd"
++  # this sets wsrep_start_position_opt
++  wsrep_recover_position "$cmd"
++
++  [ $? -ne 0 ] && exit 1 #
++
++  [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address
++
++  if [ -z "$url" ]
++  then
++    eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir"
++  else
++    eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir"
++  fi
+   if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then
+     touch "$err_log"                    # hypothetical: log was renamed but not
+@@ -857,6 +951,20 @@ do
+       I=`expr $I + 1`
+     done
+   fi
++
++  if [ -n "$wsrep_restart" ]
++  then
++    if [ $wsrep_restart -le $max_wsrep_restarts ]
++    then
++      wsrep_restart=`expr $wsrep_restart + 1`
++      log_notice "WSREP: sleeping 15 seconds before restart"
++      sleep 15
++    else
++      log_notice "WSREP: not restarting wsrep node automatically"
++      break
++    fi
++  fi
++
+   log_notice "mysqld restarted"
+ done
+diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
+new file mode 100644
+index 0000000..46f4076
+--- /dev/null
++++ b/scripts/wsrep_sst_common.sh
+@@ -0,0 +1,187 @@
++# Copyright (C) 2012-2014 Codership Oy
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to the
++# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
++# MA  02110-1301  USA.
++
++# This is a common command line parser to be sourced by other SST scripts
++
++set -u
++
++WSREP_SST_OPT_BYPASS=0
++WSREP_SST_OPT_BINLOG=""
++WSREP_SST_OPT_DATA=""
++WSREP_SST_OPT_AUTH=""
++
++while [ $# -gt 0 ]; do
++case "$1" in
++    '--address')
++        readonly WSREP_SST_OPT_ADDR="$2"
++        shift
++        ;;
++    '--auth')
++        WSREP_SST_OPT_AUTH="$2"
++        shift
++        ;;
++    '--bypass')
++        WSREP_SST_OPT_BYPASS=1
++        ;;
++    '--datadir')
++        readonly WSREP_SST_OPT_DATA="$2"
++        shift
++        ;;
++    '--defaults-file')
++        readonly WSREP_SST_OPT_CONF="$2"
++        shift
++        ;;
++    '--defaults-group-suffix')
++        readonly WSREP_SST_OPT_CONF_SUFFIX="$2"
++        shift
++        ;;
++    '--host')
++        readonly WSREP_SST_OPT_HOST="$2"
++        shift
++        ;;
++    '--local-port')
++        readonly WSREP_SST_OPT_LPORT="$2"
++        shift
++        ;;
++    '--parent')
++        readonly WSREP_SST_OPT_PARENT="$2"
++        shift
++        ;;
++    '--password')
++        WSREP_SST_OPT_PSWD="$2"
++        shift
++        ;;
++    '--port')
++        readonly WSREP_SST_OPT_PORT="$2"
++        shift
++        ;;
++    '--role')
++        readonly WSREP_SST_OPT_ROLE="$2"
++        shift
++        ;;
++    '--socket')
++        readonly WSREP_SST_OPT_SOCKET="$2"
++        shift
++        ;;
++    '--user')
++        WSREP_SST_OPT_USER="$2"
++        shift
++        ;;
++    '--gtid')
++        readonly WSREP_SST_OPT_GTID="$2"
++        shift
++        ;;
++    '--binlog')
++        WSREP_SST_OPT_BINLOG="$2"
++        shift
++        ;;
++    *) # must be command
++       # usage
++       # exit 1
++       ;;
++esac
++shift
++done
++readonly WSREP_SST_OPT_BYPASS
++readonly WSREP_SST_OPT_BINLOG
++
++# try to use my_print_defaults, mysql and mysqldump that come with the sources
++# (for MTR suite)
++SCRIPTS_DIR="$(cd $(dirname "$0"); pwd -P)"
++EXTRA_DIR="$SCRIPTS_DIR/../extra"
++CLIENT_DIR="$SCRIPTS_DIR/../client"
++
++if [ -x "$CLIENT_DIR/mysql" ]; then
++    MYSQL_CLIENT="$CLIENT_DIR/mysql"
++else
++    MYSQL_CLIENT=$(which mysql)
++fi
++
++if [ -x "$CLIENT_DIR/mysqldump" ]; then
++    MYSQLDUMP="$CLIENT_DIR/mysqldump"
++else
++    MYSQLDUMP=$(which mysqldump)
++fi
++
++if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then
++    MY_PRINT_DEFAULTS="$SCRIPTS_DIR/my_print_defaults"
++elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then
++    MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults"
++else
++    MY_PRINT_DEFAULTS=$(which my_print_defaults)
++fi
++
++# For Bug:1200727
++if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then
++    if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then
++            WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2)
++    fi
++fi
++
++if [ -n "${WSREP_SST_OPT_DATA:-}" ]
++then
++    SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress"
++else
++    SST_PROGRESS_FILE=""
++fi
++
++
++wsrep_log()
++{
++    # echo everything to stderr so that it gets into common error log
++    # deliberately made to look different from the rest of the log
++    local readonly tst="$(date +%Y%m%d\ %H:%M:%S.%N | cut -b -21)"
++    echo "WSREP_SST: $* ($tst)" >&2
++}
++
++wsrep_log_error()
++{
++    wsrep_log "[ERROR] $*"
++}
++
++wsrep_log_info()
++{
++    wsrep_log "[INFO] $*"
++}
++
++wsrep_cleanup_progress_file()
++{
++    [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null
++}
++
++wsrep_check_program()
++{
++    local prog=$1
++
++    if ! which $prog >/dev/null
++    then
++        echo "'$prog' not found in PATH"
++        return 2 # no such file or directory
++    fi
++}
++
++wsrep_check_programs()
++{
++    local ret=0
++
++    while [ $# -gt 0 ]
++    do
++        wsrep_check_program $1 || ret=$?
++        shift
++    done
++
++    return $ret
++}
+diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh
+new file mode 100644
+index 0000000..89eb755
+--- /dev/null
++++ b/scripts/wsrep_sst_mysqldump.sh
+@@ -0,0 +1,136 @@
++#!/bin/bash -e
++# Copyright (C) 2009 Codership Oy
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to the
++# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
++# MA  02110-1301  USA.
++
++# This is a reference script for mysqldump-based state snapshot tansfer
++
++. $(dirname $0)/wsrep_sst_common
++
++EINVAL=22
++
++local_ip()
++{
++    PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
++
++    [ "$1" = "127.0.0.1" ]      && return 0
++    [ "$1" = "localhost" ]      && return 0
++    [ "$1" = "$(hostname -s)" ] && return 0
++    [ "$1" = "$(hostname -f)" ] && return 0
++    [ "$1" = "$(hostname -d)" ] && return 0
++
++    # Now if ip program is not found in the path, we can't return 0 since
++    # it would block any address. Thankfully grep should fail in this case
++    ip route get "$1" | grep local >/dev/null && return 0
++
++    return 1
++}
++
++if test -z "$WSREP_SST_OPT_USER";  then wsrep_log_error "USER cannot be nil";  exit $EINVAL; fi
++if test -z "$WSREP_SST_OPT_HOST";  then wsrep_log_error "HOST cannot be nil";  exit $EINVAL; fi
++if test -z "$WSREP_SST_OPT_PORT";  then wsrep_log_error "PORT cannot be nil";  exit $EINVAL; fi
++if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi
++if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi
++if test -z "$WSREP_SST_OPT_GTID";  then wsrep_log_error "GTID cannot be nil";  exit $EINVAL; fi
++
++if local_ip $WSREP_SST_OPT_HOST && \
++   [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ]
++then
++    wsrep_log_error \
++    "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address."
++    exit $EINVAL
++fi
++
++# Check client version
++CLIENT_MINOR=$(mysql --version | cut -d ' ' -f 6 | cut -d '.' -f 2)
++if [ $CLIENT_MINOR -lt "6" ]
++then
++    $MYSQL_CLIENT --version >&2
++    wsrep_log_error "this operation requires MySQL client version 5.6.x"
++    exit $EINVAL
++fi
++
++# For Bug:1293798
++if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then
++    WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1)
++    WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2)
++fi
++AUTH="-u$WSREP_SST_OPT_USER"
++if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi
++
++STOP_WSREP="SET wsrep_on=OFF;"
++
++# NOTE: we don't use --routines here because we're dumping mysql.proc table
++MYSQLDUMP="$MYSQLDUMP $AUTH -S$WSREP_SST_OPT_SOCKET \
++--add-drop-database --add-drop-table --skip-add-locks --create-options \
++--disable-keys --extended-insert --skip-lock-tables --quick --set-charset \
++--skip-comments --flush-privileges --all-databases --events"
++
++# mysqldump cannot restore CSV tables, fix this issue
++CSV_TABLES_FIX="
++set sql_mode='';
++
++USE mysql;
++
++SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, thread_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, command_type VARCHAR(64) NOT NULL,argument MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment=\"General log\"', 'SET @dummy = 0');
++
++PREPARE stmt FROM @str;
++EXECUTE stmt;
++DROP PREPARE stmt;
++
++SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512) NOT NULL, last_insert_id INTEGER NOT NULL, insert_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment=\"Slow log\"', 'SET @dummy = 0');
++
++PREPARE stmt FROM @str;
++EXECUTE stmt;
++DROP PREPARE stmt;"
++
++SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';"
++
++MYSQL="$MYSQL_CLIENT $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\
++"--disable-reconnect --connect_timeout=10"
++
++# need to disable logging when loading the dump
++# reason is that dump contains ALTER TABLE for log tables, and
++# this causes an error if logging is enabled
++GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"`
++SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"`
++$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF"
++$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF"
++
++# commands to restore log settings
++RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;"
++RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;"
++
++# reset master for 5.6 to clear GTID_EXECUTED
++RESET_MASTER="RESET MASTER;"
++
++
++if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
++then
++    # commented out from dump command for 5.6: && echo $CSV_TABLES_FIX \
++    # error is ignored because joiner binlog might be disabled.
++    # and if joiner binlog is disabled, 'RESET MASTER' returns error
++    # ERROR 1186 (HY000) at line 2: Binlog closed, cannot RESET MASTER
++    (echo $STOP_WSREP && echo $RESET_MASTER) | $MYSQL || true
++    (echo $STOP_WSREP && $MYSQLDUMP \
++        && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \
++        && echo $SET_START_POSITION \
++        || echo "SST failed to complete;") | $MYSQL
++else
++    wsrep_log_info "Bypassing state dump."
++    echo $SET_START_POSITION | $MYSQL
++fi
++
++#
+diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh
+new file mode 100644
+index 0000000..8998f73
+--- /dev/null
++++ b/scripts/wsrep_sst_rsync.sh
+@@ -0,0 +1,329 @@
++#!/bin/bash -ue
++
++# Copyright (C) 2010-2014 Codership Oy
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to the
++# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
++# MA  02110-1301  USA.
++
++# This is a reference script for rsync-based state snapshot tansfer
++
++RSYNC_PID=
++RSYNC_CONF=
++OS=$(uname)
++[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH
++
++# Setting the path for lsof on CentOS
++export PATH="/usr/sbin:/sbin:$PATH"
++
++. $(dirname $0)/wsrep_sst_common
++
++wsrep_check_programs rsync
++
++cleanup_joiner()
++{
++    wsrep_log_info "Joiner cleanup."
++    local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0)
++    [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \
++    || :
++    rm -rf "$RSYNC_CONF"
++    rm -rf "$MAGIC_FILE"
++    rm -rf "$RSYNC_PID"
++    wsrep_log_info "Joiner cleanup done."
++    if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
++        wsrep_cleanup_progress_file
++    fi
++}
++
++check_pid()
++{
++    local pid_file=$1
++    [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1
++}
++
++check_pid_and_port()
++{
++    local pid_file=$1
++    local rsync_pid=$2
++    local rsync_port=$3
++
++    local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \
++        grep "(LISTEN)")
++    local is_rsync=$(echo $port_info | \
++        grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null)
++
++    if [ -n "$port_info" -a -z "$is_rsync" ]; then
++        wsrep_log_error "rsync daemon port '$rsync_port' has been taken"
++        exit 16 # EBUSY
++    fi
++    check_pid $pid_file && \
++        [ -n "$port_info" ] && [ -n "$is_rsync" ] && \
++        [ $(cat $pid_file) -eq $rsync_pid ]
++}
++
++MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete"
++rm -rf "$MAGIC_FILE"
++
++BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar"
++BINLOG_N_FILES=1
++rm -f "$BINLOG_TAR_FILE" || :
++
++if ! [ -z $WSREP_SST_OPT_BINLOG ]
++then
++    BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG)
++    BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG)
++fi
++
++WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
++# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf
++if [ -z "$WSREP_LOG_DIR" ]; then
++    WSREP_LOG_DIR=$($MY_PRINT_DEFAULTS --defaults-file \
++                   "$WSREP_SST_OPT_CONF" mysqld server mysqld-5.6 \
++                    | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \
++                    | cut -b 29- )
++fi
++
++if [ -n "$WSREP_LOG_DIR" ]; then
++    # handle both relative and absolute paths
++    WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P)
++else
++    # default to datadir
++    WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P)
++fi
++
++# Old filter - include everything except selected
++# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \
++#         --exclude '*.conf' --exclude core --exclude 'galera.*' \
++#         --exclude grastate.txt --exclude '*.pem' \
++#         --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index')
++
++# New filter - exclude everything except dirs (schemas) and innodb files
++FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes'
++        -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*')
++
++if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
++then
++
++    if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
++    then
++
++        FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed"
++        rm -rf "$FLUSHED"
++
++        # Use deltaxfer only for WAN
++        inv=$(basename $0)
++        [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \
++                                           || WHOLE_FILE_OPT="--whole-file"
++
++        echo "flush tables"
++
++        # wait for tables flushed and state ID written to the file
++        while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1
++        do
++            sleep 0.2
++        done
++
++        STATE="$(cat $FLUSHED)"
++        rm -rf "$FLUSHED"
++
++        sync
++
++        if ! [ -z $WSREP_SST_OPT_BINLOG ]
++        then
++            # Prepare binlog files
++            pushd $BINLOG_DIRNAME &> /dev/null
++            binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index)
++            binlog_files=""
++            for ii in $binlog_files_full
++            do
++                binlog_files="$binlog_files $(basename $ii)"
++            done
++            if ! [ -z "$binlog_files" ]
++            then
++                wsrep_log_info "Preparing binlog files for transfer:"
++                tar -cvf $BINLOG_TAR_FILE $binlog_files >&2
++            fi
++            popd &> /dev/null
++        fi
++
++        # first, the normal directories, so that we can detect incompatible protocol
++        RC=0
++        rsync --owner --group --perms --links --specials \
++              --ignore-times --inplace --dirs --delete --quiet \
++              $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \
++              rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$?
++
++        if [ "$RC" -ne 0 ]; then
++            wsrep_log_error "rsync returned code $RC:"
++
++            case $RC in
++            12) RC=71  # EPROTO
++                wsrep_log_error \
++                "rsync server on the other end has incompatible protocol. " \
++                "Make sure you have the same version of rsync on all nodes."
++                ;;
++            22) RC=12  # ENOMEM
++                ;;
++            *)  RC=255 # unknown error
++                ;;
++            esac
++            exit $RC
++        fi
++
++        # second, we transfer InnoDB log files
++        rsync --owner --group --perms --links --specials \
++              --ignore-times --inplace --dirs --delete --quiet \
++              $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \
++              rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$?
++
++        if [ $RC -ne 0 ]; then
++            wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:"
++            exit 255 # unknown error
++        fi
++
++        # then, we parallelize the transfer of database directories, use . so that pathconcatenation works
++        pushd "$WSREP_SST_OPT_DATA" >/dev/null
++
++        count=1
++        [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo)
++        [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu)
++
++        find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \
++             rsync --owner --group --perms --links --specials \
++             --ignore-times --inplace --recursive --delete --quiet \
++             $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \
++             rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$?
++
++        popd >/dev/null
++
++        if [ $RC -ne 0 ]; then
++            wsrep_log_error "find/rsync returned code $RC:"
++            exit 255 # unknown error
++        fi
++
++    else # BYPASS
++        wsrep_log_info "Bypassing state dump."
++        STATE="$WSREP_SST_OPT_GTID"
++    fi
++
++    echo "continue" # now server can resume updating data
++
++    echo "$STATE" > "$MAGIC_FILE"
++    rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR
++
++    echo "done $STATE"
++
++elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ]
++then
++    wsrep_check_programs lsof
++
++    touch $SST_PROGRESS_FILE
++    MYSQLD_PID=$WSREP_SST_OPT_PARENT
++
++    MODULE="rsync_sst"
++
++    RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid"
++
++    if check_pid $RSYNC_PID
++    then
++        wsrep_log_error "rsync daemon already running."
++        exit 114 # EALREADY
++    fi
++    rm -rf "$RSYNC_PID"
++
++    ADDR=$WSREP_SST_OPT_ADDR
++    RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }')
++    if [ -z "$RSYNC_PORT" ]
++    then
++        RSYNC_PORT=4444
++        ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT"
++    fi
++
++    trap "exit 32" HUP PIPE
++    trap "exit 3"  INT TERM ABRT
++    trap cleanup_joiner EXIT
++
++    RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
++
++cat << EOF > "$RSYNC_CONF"
++pid file = $RSYNC_PID
++use chroot = no
++read only = no
++timeout = 300
++[$MODULE]
++    path = $WSREP_SST_OPT_DATA
++[$MODULE-log_dir]
++    path = $WSREP_LOG_DIR
++EOF
++
++#    rm -rf "$DATA"/ib_logfile* # we don't want old logs around
++
++    # listen at all interfaces (for firewalled setups)
++    rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" &
++    RSYNC_REAL_PID=$!
++
++    until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT
++    do
++        sleep 0.2
++    done
++
++    echo "ready $ADDR/$MODULE"
++
++    # wait for SST to complete by monitoring magic file
++    while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \
++          ps -p $MYSQLD_PID >/dev/null
++    do
++        sleep 1
++    done
++
++    if ! ps -p $MYSQLD_PID >/dev/null
++    then
++        wsrep_log_error \
++        "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly."
++        exit 32
++    fi
++
++    if ! [ -z $WSREP_SST_OPT_BINLOG ]
++    then
++
++        pushd $BINLOG_DIRNAME &> /dev/null
++        if [ -f $BINLOG_TAR_FILE ]
++        then
++            # Clean up old binlog files first
++            rm -f ${BINLOG_FILENAME}.*
++            wsrep_log_info "Extracting binlog files:"
++            tar -xvf $BINLOG_TAR_FILE >&2
++            for ii in $(ls -1 ${BINLOG_FILENAME}.*)
++            do
++                echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index
++            done
++        fi
++        popd &> /dev/null
++    fi
++    if [ -r "$MAGIC_FILE" ]
++    then
++        cat "$MAGIC_FILE" # output UUID:seqno
++    else
++        # this message should cause joiner to abort
++        echo "rsync process ended without creating '$MAGIC_FILE'"
++    fi
++    wsrep_cleanup_progress_file
++#    cleanup_joiner
++else
++    wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'"
++    exit 22 # EINVAL
++fi
++
++rm -f $BINLOG_TAR_FILE || :
++
++exit 0
+diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh
+new file mode 100644
+index 0000000..1d1267d
+--- /dev/null
++++ b/scripts/wsrep_sst_xtrabackup-v2.sh
+@@ -0,0 +1,930 @@
++#!/bin/bash -ue
++# Copyright (C) 2013 Percona Inc
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to the
++# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
++# MA  02110-1301  USA.
++
++# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html 
++# Make sure to read that before proceeding!
++
++
++
++
++. $(dirname $0)/wsrep_sst_common
++
++ealgo=""
++ekey=""
++ekeyfile=""
++encrypt=0
++nproc=1
++ecode=0
++XTRABACKUP_PID=""
++SST_PORT=""
++REMOTEIP=""
++tcert=""
++tpem=""
++tkey=""
++sockopt=""
++progress=""
++ttime=0
++totime=0
++lsn=""
++incremental=0
++ecmd=""
++rlimit=""
++# Initially
++stagemsg="${WSREP_SST_OPT_ROLE}"
++cpat=""
++speciald=0
++ib_home_dir=""
++ib_log_dir=""
++
++sfmt="tar"
++strmcmd=""
++tfmt=""
++tcmd=""
++rebuild=0
++rebuildcmd=""
++payload=0
++pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' "
++pvopts="-f  -i 10 -N $WSREP_SST_OPT_ROLE "
++STATDIR=""
++uextra=0
++disver=""
++
++tmpopts=""
++itmpdir=""
++xtmpdir=""
++
++scomp=""
++sdecomp=""
++
++if which pv &>/dev/null && pv --help | grep -q FORMAT;then 
++    pvopts+=$pvformat
++fi
++pcmd="pv $pvopts"
++declare -a RC
++
++INNOBACKUPEX_BIN=innobackupex
++readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ })
++DATA="${WSREP_SST_OPT_DATA}"
++INFO_FILE="xtrabackup_galera_info"
++IST_FILE="xtrabackup_ist"
++MAGIC_FILE="${DATA}/${INFO_FILE}"
++
++# Setting the path for ss and ip
++export PATH="/usr/sbin:/sbin:$PATH"
++
++timeit(){
++    local stage=$1
++    shift
++    local cmd="$@"
++    local x1 x2 took extcode
++
++    if [[ $ttime -eq 1 ]];then 
++        x1=$(date +%s)
++        wsrep_log_info "Evaluating $cmd"
++        eval "$cmd"
++        extcode=$?
++        x2=$(date +%s)
++        took=$(( x2-x1 ))
++        wsrep_log_info "NOTE: $stage took $took seconds"
++        totime=$(( totime+took ))
++    else 
++        wsrep_log_info "Evaluating $cmd"
++        eval "$cmd"
++        extcode=$?
++    fi
++    return $extcode
++}
++
++get_keys()
++{
++    # $encrypt -eq 1 is for internal purposes only
++    if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then 
++        return 
++    fi
++
++    if [[ $encrypt -eq 0 ]];then 
++        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then
++            wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
++        fi
++        return
++    fi
++
++    if [[ $sfmt == 'tar' ]];then
++        wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format"
++        encrypt=-1
++        return
++    fi
++
++    wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4"
++
++    if [[ -z $ealgo ]];then
++        wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
++        exit 3
++    fi
++
++    if [[ -z $ekey && ! -r $ekeyfile ]];then
++        wsrep_log_error "FATAL: Either key or keyfile must be readable"
++        exit 3
++    fi
++
++    if [[ -z $ekey ]];then
++        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile"
++    else
++        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
++    fi
++
++    if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
++        ecmd+=" -d"
++    fi
++
++    stagemsg+="-XB-Encrypted"
++}
++
++get_transfer()
++{
++    if [[ -z $SST_PORT ]];then 
++        TSST_PORT=4444
++    else 
++        TSST_PORT=$SST_PORT
++    fi
++
++    if [[ $tfmt == 'nc' ]];then
++        if [[ ! -x `which nc` ]];then 
++            wsrep_log_error "nc(netcat) not found in path: $PATH"
++            exit 2
++        fi
++        wsrep_log_info "Using netcat as streamer"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            tcmd="nc -dl ${TSST_PORT}"
++        else
++            tcmd="nc ${REMOTEIP} ${TSST_PORT}"
++        fi
++    else
++        tfmt='socat'
++        wsrep_log_info "Using socat as streamer"
++        if [[ ! -x `which socat` ]];then 
++            wsrep_log_error "socat not found in path: $PATH"
++            exit 2
++        fi
++
++        if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then 
++            wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer"
++            encrypt=-1
++        fi
++
++        if [[ $encrypt -eq 2 ]];then 
++            wsrep_log_info "Using openssl based encryption with socat: with crt and pem"
++            if [[ -z $tpem || -z $tcert ]];then 
++                wsrep_log_error "Both PEM and CRT files required"
++                exit 22
++            fi
++            stagemsg+="-OpenSSL-Encrypted-2"
++            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++                wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert"
++                tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio"
++            else
++                wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert"
++                tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}"
++            fi
++        elif [[ $encrypt -eq 3 ]];then
++            wsrep_log_info "Using openssl based encryption with socat: with key and crt"
++            if [[ -z $tpem || -z $tkey ]];then 
++                wsrep_log_error "Both certificate and key files required"
++                exit 22
++            fi
++            stagemsg+="-OpenSSL-Encrypted-3"
++            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++                wsrep_log_info "Decrypting with certificate $tpem, key $tkey"
++                tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio"
++            else
++                wsrep_log_info "Encrypting with certificate $tpem, key $tkey"
++                tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}"
++            fi
++
++        else 
++            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++                tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
++            else
++                tcmd="socat -u stdio TCP:${REMOTEIP}:${TSST_PORT}${sockopt}"
++            fi
++        fi
++    fi
++
++}
++
++parse_cnf()
++{
++    local group=$1
++    local var=$2
++    reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-)
++    if [[ -z $reval ]];then 
++        [[ -n $3 ]] && reval=$3
++    fi
++    echo $reval
++}
++
++get_footprint()
++{
++    pushd $WSREP_SST_OPT_DATA 1>/dev/null
++    payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }')
++    if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then 
++        # QuickLZ has around 50% compression ratio
++        # When compression/compaction used, the progress is only an approximate.
++        payload=$(( payload*1/2 ))
++    fi
++    popd 1>/dev/null
++    pcmd+=" -s $payload"
++    adjust_progress
++}
++
++adjust_progress()
++{
++    if [[ -n $progress && $progress != '1' ]];then 
++        if [[ -e $progress ]];then 
++            pcmd+=" 2>>$progress"
++        else 
++            pcmd+=" 2>$progress"
++        fi
++    elif [[ -z $progress && -n $rlimit  ]];then 
++            # When rlimit is non-zero
++            pcmd="pv -q"
++    fi 
++
++    if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
++        wsrep_log_info "Rate-limiting SST to $rlimit"
++        pcmd+=" -L \$rlimit"
++    fi
++}
++
++read_cnf()
++{
++    sfmt=$(parse_cnf sst streamfmt "xbstream")
++    tfmt=$(parse_cnf sst transferfmt "socat")
++    tcert=$(parse_cnf sst tca "")
++    tpem=$(parse_cnf sst tcert "")
++    tkey=$(parse_cnf sst tkey "")
++    encrypt=$(parse_cnf sst encrypt 0)
++    sockopt=$(parse_cnf sst sockopt "")
++    progress=$(parse_cnf sst progress "")
++    rebuild=$(parse_cnf sst rebuild 0)
++    ttime=$(parse_cnf sst time 0)
++    cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*gvwstate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$')
++    incremental=$(parse_cnf sst incremental 0)
++    ealgo=$(parse_cnf xtrabackup encrypt "")
++    ekey=$(parse_cnf xtrabackup encrypt-key "")
++    ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "")
++    scomp=$(parse_cnf sst compressor "")
++    sdecomp=$(parse_cnf sst decompressor "")
++
++
++    # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html 
++    if [[ -z $ealgo ]];then
++        ealgo=$(parse_cnf sst encrypt-algo "")
++        ekey=$(parse_cnf sst encrypt-key "")
++        ekeyfile=$(parse_cnf sst encrypt-key-file "")
++    fi
++    rlimit=$(parse_cnf sst rlimit "")
++    uextra=$(parse_cnf sst use-extra 0)
++    speciald=$(parse_cnf sst sst-special-dirs 1)
++    iopts=$(parse_cnf sst inno-backup-opts "")
++    iapts=$(parse_cnf sst inno-apply-opts "")
++    impts=$(parse_cnf sst inno-move-opts "")
++    stimeout=$(parse_cnf sst sst-initial-timeout 100)
++}
++
++get_stream()
++{
++    if [[ $sfmt == 'xbstream' ]];then 
++        wsrep_log_info "Streaming with xbstream"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            strmcmd="xbstream -x"
++        else
++            strmcmd="xbstream -c \${INFO_FILE}"
++        fi
++    else
++        sfmt="tar"
++        wsrep_log_info "Streaming with tar"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            strmcmd="tar xfi - "
++        else
++            strmcmd="tar cf - \${INFO_FILE} "
++        fi
++
++    fi
++}
++
++get_proc()
++{
++    set +e
++    nproc=$(grep -c processor /proc/cpuinfo)
++    [[ -z $nproc || $nproc -eq 0 ]] && nproc=1
++    set -e
++}
++
++sig_joiner_cleanup()
++{
++    wsrep_log_error "Removing $MAGIC_FILE file due to signal"
++    rm -f "$MAGIC_FILE"
++}
++
++cleanup_joiner()
++{
++    # Since this is invoked just after exit NNN
++    local estatus=$?
++    if [[ $estatus -ne 0 ]];then 
++        wsrep_log_error "Cleanup after exit with status:$estatus"
++    fi
++    if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
++        wsrep_log_info "Removing the sst_in_progress file"
++        wsrep_cleanup_progress_file
++    fi
++    if [[ -n $progress && -p $progress ]];then 
++        wsrep_log_info "Cleaning up fifo file $progress"
++        rm $progress
++    fi
++    if [[ -n ${STATDIR:-} ]];then 
++       [[ -d $STATDIR ]] && rm -rf $STATDIR
++    fi
++}
++
++check_pid()
++{
++    local pid_file="$1"
++    [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1
++}
++
++cleanup_donor()
++{
++    # Since this is invoked just after exit NNN
++    local estatus=$?
++    if [[ $estatus -ne 0 ]];then 
++        wsrep_log_error "Cleanup after exit with status:$estatus"
++    fi
++
++    if [[ -n ${XTRABACKUP_PID:-} ]];then 
++        if check_pid $XTRABACKUP_PID
++        then
++            wsrep_log_error "xtrabackup process is still running. Killing... "
++            kill_xtrabackup
++        fi
++
++    fi
++    rm -f ${DATA}/${IST_FILE} || true
++
++    if [[ -n $progress && -p $progress ]];then 
++        wsrep_log_info "Cleaning up fifo file $progress"
++        rm -f $progress || true
++    fi
++
++    wsrep_log_info "Cleaning up temporary directories"
++
++    if [[ -n $xtmpdir ]];then 
++       [[ -d $xtmpdir ]] &&  rm -rf $xtmpdir || true
++    fi
++
++    if [[ -n $itmpdir ]];then 
++       [[ -d $itmpdir ]] &&  rm -rf $itmpdir || true
++    fi
++}
++
++kill_xtrabackup()
++{
++    local PID=$(cat $XTRABACKUP_PID)
++    [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || :
++    wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID"
++    rm -f "$XTRABACKUP_PID" || true
++}
++
++setup_ports()
++{
++    if [[ "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
++        SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }')
++        REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }')
++        lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }')
++    else
++        SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }')
++    fi
++}
++
++# waits ~10 seconds for nc to open the port and then reports ready
++# (regardless of timeout)
++wait_for_listen()
++{
++    local PORT=$1
++    local ADDR=$2
++    local MODULE=$3
++    for i in {1..50}
++    do
++        ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
++        sleep 0.2
++    done
++    if [[ $incremental -eq 1 ]];then 
++        echo "ready ${ADDR}/${MODULE}/$lsn"
++    else 
++        echo "ready ${ADDR}/${MODULE}"
++    fi
++}
++
++check_extra()
++{
++    local use_socket=1
++    if [[ $uextra -eq 1 ]];then 
++        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then 
++            local eport=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2)
++            if [[ -n $eport ]];then 
++                # Xtrabackup works only locally.
++                # Hence, setting host to 127.0.0.1 unconditionally. 
++                wsrep_log_info "SST through extra_port $eport"
++                INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
++                use_socket=0
++            else 
++                wsrep_log_error "Extra port $eport null, failing"
++                exit 1
++            fi
++        else 
++            wsrep_log_info "Thread pool not set, ignore the option use_extra"
++        fi
++    fi
++    if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
++        INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
++    fi
++}
++
++recv_joiner()
++{
++    local dir=$1
++    local msg=$2 
++    local tmt=$3
++    local ltcmd
++
++    pushd ${dir} 1>/dev/null
++    set +e
++
++    if [[ $tmt -gt 0 && -x `which timeout` ]];then 
++        if timeout --help | grep -q -- '-k';then 
++            ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd"
++        else 
++            ltcmd="timeout $tmt $tcmd"
++        fi
++        timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
++    else 
++        timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
++    fi
++
++    set -e
++    popd 1>/dev/null 
++
++    if [[ ${RC[0]} -eq 124 ]];then 
++        wsrep_log_error "Possible timeout in receving first data from donor in gtid stage"
++        exit 32
++    fi
++
++    for ecode in "${RC[@]}";do 
++        if [[ $ecode -ne 0 ]];then 
++            wsrep_log_error "Error while getting data from donor node: " \
++                            "exit codes: ${RC[@]}"
++            exit 32
++        fi
++    done
++
++    if [ ! -r "${MAGIC_FILE}" ];then
++        # this message should cause joiner to abort
++        wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'"
++        wsrep_log_info "Contents of datadir" 
++        wsrep_log_info "$(ls -l ${dir}/*)"
++        exit 32
++    fi
++}
++
++
++send_donor()
++{
++    local dir=$1
++    local msg=$2 
++
++    pushd ${dir} 1>/dev/null
++    set +e
++    timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
++    set -e
++    popd 1>/dev/null 
++
++
++    for ecode in "${RC[@]}";do 
++        if [[ $ecode -ne 0 ]];then 
++            wsrep_log_error "Error while getting data from donor node: " \
++                            "exit codes: ${RC[@]}"
++            exit 32
++        fi
++    done
++
++}
++
++if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then 
++    wsrep_log_error "innobackupex not in path: $PATH"
++    exit 2
++fi
++
++rm -f "${MAGIC_FILE}"
++
++if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then 
++    wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
++    exit 22
++fi
++
++read_cnf
++setup_ports
++get_stream
++get_transfer
++
++if ${INNOBACKUPEX_BIN} /tmp --help  | grep -q -- '--version-check'; then 
++    disver="--no-version-check"
++fi
++
++
++INNOEXTRA=""
++INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
++INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $impts  --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log"
++INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log"
++
++if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
++then
++    trap cleanup_donor EXIT
++
++    if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
++    then
++
++        if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then 
++            xtmpdir=$(mktemp -d)
++            tmpopts=" --tmpdir=$xtmpdir "
++            wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory"
++        fi
++
++        itmpdir=$(mktemp -d)
++        wsrep_log_info "Using $itmpdir as innobackupex temporary directory"
++
++        if [ "${AUTH[0]}" != "(null)" ]; then
++           INNOEXTRA+=" --user=${AUTH[0]}"
++       fi
++
++        if [ ${#AUTH[*]} -eq 2 ]; then
++           INNOEXTRA+=" --password=${AUTH[1]}"
++        elif [ "${AUTH[0]}" != "(null)" ]; then
++           # Empty password, used for testing, debugging etc.
++           INNOEXTRA+=" --password="
++        fi
++
++        get_keys
++        if [[ $encrypt -eq 1 ]];then
++            if [[ -n $ekey ]];then
++                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey "
++            else 
++                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile "
++            fi
++        fi
++
++        if [[ -n $lsn ]];then 
++                INNOEXTRA+=" --incremental --incremental-lsn=$lsn "
++        fi
++
++        check_extra
++
++        wsrep_log_info "Streaming GTID file before SST"
++
++        echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}"
++
++        ttcmd="$tcmd"
++
++        if [[ $encrypt -eq 1 ]];then
++            if [[ -n $scomp ]];then 
++                tcmd=" $ecmd | $scomp | $tcmd "
++            else 
++                tcmd=" $ecmd | $tcmd "
++            fi
++        elif [[ -n $scomp ]];then 
++            tcmd=" $scomp | $tcmd "
++        fi
++
++
++        send_donor $DATA "${stagemsg}-gtid"
++
++        tcmd="$ttcmd"
++        if [[ -n $progress ]];then 
++            get_footprint
++            tcmd="$pcmd | $tcmd"
++        elif [[ -n $rlimit ]];then 
++            adjust_progress
++            tcmd="$pcmd | $tcmd"
++        fi
++
++        wsrep_log_info "Sleeping before data transfer for SST"
++        sleep 10
++
++        wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}"
++
++        if [[ -n $scomp ]];then 
++            tcmd="$scomp | $tcmd"
++        fi
++
++        set +e
++        timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
++        set -e
++
++        if [ ${RC[0]} -ne 0 ]; then
++          wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \
++                          "Check ${DATA}/innobackup.backup.log"
++          exit 22
++        elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then 
++          wsrep_log_error "$tcmd finished with error: ${RC[1]}"
++          exit 22
++        fi
++
++        # innobackupex implicitly writes PID to fixed location in $xtmpdir
++        XTRABACKUP_PID="$xtmpdir/xtrabackup_pid"
++
++
++    else # BYPASS FOR IST
++
++        wsrep_log_info "Bypassing the SST for IST"
++        echo "continue" # now server can resume updating data
++        echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}"
++        echo "1" > "${DATA}/${IST_FILE}"
++        get_keys
++        if [[ $encrypt -eq 1 ]];then
++            if [[ -n $scomp ]];then 
++                tcmd=" $ecmd | $scomp | $tcmd "
++            else
++                tcmd=" $ecmd | $tcmd "
++            fi
++        elif [[ -n $scomp ]];then 
++            tcmd=" $scomp | $tcmd "
++        fi
++        strmcmd+=" \${IST_FILE}"
++
++        send_donor $DATA "${stagemsg}-IST"
++
++    fi
++
++    echo "done ${WSREP_SST_OPT_GTID}"
++    wsrep_log_info "Total time on donor: $totime seconds"
++
++elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ]
++then
++    [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
++    [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE
++
++    if [[ $speciald -eq 1 ]];then 
++        ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "")
++        ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "")
++        if [[ -z $ib_home_dir && -z $ib_log_dir ]];then 
++            speciald=0
++        fi
++    fi
++
++    stagemsg="Joiner-Recv"
++
++    if [[ ! -e ${DATA}/ibdata1 ]];then 
++        incremental=0
++    fi
++
++    if [[ $incremental -eq 1 ]];then 
++        wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet"
++        lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ')
++        wsrep_log_info "Recovered LSN: $lsn"
++    fi
++
++    sencrypted=1
++    nthreads=1
++
++    MODULE="xtrabackup_sst"
++
++    rm -f "${DATA}/${IST_FILE}"
++
++    # May need xtrabackup_checkpoints later on
++    rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info  ${DATA}/xtrabackup_logfile
++
++    ADDR=${WSREP_SST_OPT_ADDR}
++    if [ -z "${SST_PORT}" ]
++    then
++        SST_PORT=4444
++        ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}"
++    fi
++
++    wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} &
++
++    trap sig_joiner_cleanup HUP PIPE INT TERM
++    trap cleanup_joiner EXIT
++
++    if [[ -n $progress ]];then 
++        adjust_progress
++        tcmd+=" | $pcmd"
++    fi
++
++    if [[ $incremental -eq 1 ]];then 
++        BDATA=$DATA
++        DATA=$(mktemp -d)
++        MAGIC_FILE="${DATA}/${INFO_FILE}"
++    fi
++
++    get_keys
++    if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then
++        if [[ -n $sdecomp ]];then 
++            strmcmd=" $sdecomp | $ecmd | $strmcmd"
++        else 
++            strmcmd=" $ecmd | $strmcmd"
++        fi
++    elif [[ -n $sdecomp ]];then 
++            strmcmd=" $sdecomp | $strmcmd"
++    fi
++
++    STATDIR=$(mktemp -d)
++    MAGIC_FILE="${STATDIR}/${INFO_FILE}"
++    recv_joiner $STATDIR  "${stagemsg}-gtid" $stimeout
++
++    if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null
++    then
++        wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." 
++        exit 32
++    fi
++
++    if [ ! -r "${STATDIR}/${IST_FILE}" ]
++    then
++        wsrep_log_info "Proceeding with SST"
++
++        if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then 
++            wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST"
++        fi
++
++        if [[ $incremental -ne 1 ]];then 
++            if [[ $speciald -eq 1 ]];then 
++                wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories"
++                find $ib_home_dir $ib_log_dir $DATA -mindepth 1  -regex $cpat  -prune  -o -exec rm -rfv {} 1>&2 \+
++            else 
++                wsrep_log_info "Cleaning the existing datadir"
++                find $DATA -mindepth 1  -regex $cpat  -prune  -o -exec rm -rfv {} 1>&2 \+
++            fi
++            tempdir=$(parse_cnf mysqld log-bin "")
++            if [[ -n ${tempdir:-} ]];then
++                binlog_dir=$(dirname $tempdir)
++                binlog_file=$(basename $tempdir)
++                if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then
++                    pattern="$binlog_dir/$binlog_file\.[0-9]+$"
++                    wsrep_log_info "Cleaning the binlog directory $binlog_dir as well"
++                    find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+
++                    rm $binlog_dir/*.index || true
++                fi
++            fi
++
++        else
++            wsrep_log_info "Removing existing ib_logfile files"
++            rm -f ${BDATA}/ib_logfile*
++        fi
++
++
++        if [[ $speciald -eq 1 ]];then 
++            mkdir -p ${DATA}/.sst
++            TDATA=${DATA}
++            DATA="${DATA}/.sst"
++        fi
++
++
++        MAGIC_FILE="${DATA}/${INFO_FILE}"
++        recv_joiner $DATA "${stagemsg}-SST" 0
++
++        get_proc
++
++        # Rebuild indexes for compact backups
++        if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then 
++            wsrep_log_info "Index compaction detected"
++            rebuild=1
++        fi
++
++        if [[ $rebuild -eq 1 ]];then 
++            nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc)
++            wsrep_log_info "Rebuilding during prepare with $nthreads threads"
++            rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads"
++        fi
++
++        if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then
++
++            wsrep_log_info "Compressed qpress files found"
++
++            if [[ ! -x `which qpress` ]];then 
++                wsrep_log_error "qpress not found in path: $PATH"
++                exit 22
++            fi
++
++            if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then
++                count=$(find ${DATA} -type f -name '*.qp' | wc -l)
++                count=$(( count*2 ))
++                if pv --help | grep -q FORMAT;then 
++                    pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'"
++                else 
++                    pvopts="-f -s $count -l -N Decompression"
++                fi
++                pcmd="pv $pvopts"
++                adjust_progress
++                dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d"
++            else 
++                dcmd="xargs -n 2 qpress -T${nproc}d"
++            fi
++
++
++            # Decompress the qpress files 
++            wsrep_log_info "Decompression with $nproc threads"
++            timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd"
++            extcode=$?
++
++            if [[ $extcode -eq 0 ]];then
++                wsrep_log_info "Removing qpress files after decompression"
++                find ${DATA} -type f -name '*.qp' -delete 
++                if [[ $? -ne 0 ]];then 
++                    wsrep_log_error "Something went wrong with deletion of qpress files. Investigate"
++                fi
++            else
++                wsrep_log_error "Decompression failed. Exit code: $extcode"
++                exit 22
++            fi
++        fi
++
++
++        if  [[ ! -z $WSREP_SST_OPT_BINLOG ]];then
++
++            BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG)
++            BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG)
++
++            # To avoid comparing data directory and BINLOG_DIRNAME 
++            mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true
++
++            pushd $BINLOG_DIRNAME &>/dev/null
++            for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do
++                echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index
++            done
++            popd &> /dev/null
++
++        fi
++
++        if [[ $incremental -eq 1 ]];then 
++            # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues.
++            INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} \
++                --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log"
++        fi
++
++        wsrep_log_info "Preparing the backup at ${DATA}"
++        timeit "Xtrabackup prepare stage" "$INNOAPPLY"
++
++        if [ $? -ne 0 ];
++        then
++            wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" 
++            exit 22
++        fi
++
++        if [[ $speciald -eq 1 ]];then 
++            MAGIC_FILE="${TDATA}/${INFO_FILE}"
++            set +e
++            rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log
++            set -e
++            wsrep_log_info "Moving the backup to ${TDATA}"
++            timeit "Xtrabackup move stage" "$INNOMOVE"
++            if [[ $? -eq 0 ]];then 
++                wsrep_log_info "Move successful, removing ${DATA}"
++                rm -rf $DATA
++                DATA=${TDATA}
++            else 
++                wsrep_log_error "Move failed, keeping ${DATA} for further diagnosis"
++                wsrep_log_error "Check ${DATA}/innobackup.move.log for details"
++            fi
++        fi
++
++        if [[ $incremental -eq 1 ]];then 
++            wsrep_log_info "Cleaning up ${DATA} after incremental SST"
++            [[ -d ${DATA} ]] && rm -rf ${DATA}
++            DATA=$BDATA
++        fi
++
++    else 
++        wsrep_log_info "${IST_FILE} received from donor: Running IST"
++    fi
++
++    if [[ ! -r ${MAGIC_FILE} ]];then 
++        wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable"
++        exit 2
++    fi
++    cat "${MAGIC_FILE}" # output UUID:seqno
++    wsrep_log_info "Total time on joiner: $totime seconds"
++fi
++
++exit 0
+diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh
+new file mode 100644
+index 0000000..05dbcea
+--- /dev/null
++++ b/scripts/wsrep_sst_xtrabackup.sh
+@@ -0,0 +1,715 @@
++#!/bin/bash -ue
++# Copyright (C) 2013 Percona Inc
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to the
++# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
++# MA  02110-1301  USA.
++
++# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html 
++# Make sure to read that before proceeding!
++
++
++
++
++. $(dirname $0)/wsrep_sst_common
++
++ealgo=""
++ekey=""
++ekeyfile=""
++encrypt=0
++nproc=1
++ecode=0
++XTRABACKUP_PID=""
++SST_PORT=""
++REMOTEIP=""
++tcert=""
++tpem=""
++sockopt=""
++progress=""
++ttime=0
++totime=0
++lsn=""
++incremental=0
++ecmd=""
++rlimit=""
++
++sfmt="tar"
++strmcmd=""
++tfmt=""
++tcmd=""
++rebuild=0
++rebuildcmd=""
++payload=0
++pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' "
++pvopts="-f  -i 10 -N $WSREP_SST_OPT_ROLE "
++uextra=0
++
++if which pv &>/dev/null && pv --help | grep -q FORMAT;then 
++    pvopts+=$pvformat
++fi
++pcmd="pv $pvopts"
++declare -a RC
++
++INNOBACKUPEX_BIN=innobackupex
++readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ })
++DATA="${WSREP_SST_OPT_DATA}"
++INFO_FILE="xtrabackup_galera_info"
++IST_FILE="xtrabackup_ist"
++MAGIC_FILE="${DATA}/${INFO_FILE}"
++
++# Setting the path for ss and ip
++export PATH="/usr/sbin:/sbin:$PATH"
++
++timeit(){
++    local stage=$1
++    shift
++    local cmd="$@"
++    local x1 x2 took extcode
++
++    if [[ $ttime -eq 1 ]];then 
++        x1=$(date +%s)
++        wsrep_log_info "Evaluating $cmd"
++        eval "$cmd"
++        extcode=$?
++        x2=$(date +%s)
++        took=$(( x2-x1 ))
++        wsrep_log_info "NOTE: $stage took $took seconds"
++        totime=$(( totime+took ))
++    else 
++        wsrep_log_info "Evaluating $cmd"
++        eval "$cmd"
++        extcode=$?
++    fi
++    return $extcode
++}
++
++get_keys()
++{
++    if [[ $encrypt -eq 2 ]];then 
++        return 
++    fi
++
++    if [[ $encrypt -eq 0 ]];then 
++        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then
++            wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
++        fi
++        return
++    fi
++
++    if [[ $sfmt == 'tar' ]];then
++        wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format"
++        encrypt=0
++        return
++    fi
++
++    wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4"
++
++    if [[ -z $ealgo ]];then
++        wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
++        exit 3
++    fi
++
++    if [[ -z $ekey && ! -r $ekeyfile ]];then
++        wsrep_log_error "FATAL: Either key or keyfile must be readable"
++        exit 3
++    fi
++
++    if [[ -z $ekey ]];then
++        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile"
++    else
++        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
++    fi
++
++    if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
++        ecmd+=" -d"
++    fi
++}
++
++get_transfer()
++{
++    if [[ -z $SST_PORT ]];then 
++        TSST_PORT=4444
++    else 
++        TSST_PORT=$SST_PORT
++    fi
++
++    if [[ $tfmt == 'nc' ]];then
++        if [[ ! -x `which nc` ]];then 
++            wsrep_log_error "nc(netcat) not found in path: $PATH"
++            exit 2
++        fi
++        wsrep_log_info "Using netcat as streamer"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            tcmd="nc -dl ${TSST_PORT}"
++        else
++            tcmd="nc ${REMOTEIP} ${TSST_PORT}"
++        fi
++    else
++        tfmt='socat'
++        wsrep_log_info "Using socat as streamer"
++        if [[ ! -x `which socat` ]];then 
++            wsrep_log_error "socat not found in path: $PATH"
++            exit 2
++        fi
++
++        if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then 
++            wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer"
++            encrypt=0
++        fi
++
++        if [[ $encrypt -eq 2 ]];then 
++            wsrep_log_info "Using openssl based encryption with socat"
++            if [[ -z $tpem || -z $tcert ]];then 
++                wsrep_log_error "Both PEM and CRT files required"
++                exit 22
++            fi
++            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++                wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert"
++                tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio"
++            else
++                wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert"
++                tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}"
++            fi
++        else 
++            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++                tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
++            else
++                tcmd="socat -u stdio TCP:${REMOTEIP}:${TSST_PORT}${sockopt}"
++            fi
++        fi
++    fi
++
++}
++
++parse_cnf()
++{
++    local group=$1
++    local var=$2
++    reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-)
++    if [[ -z $reval ]];then 
++        [[ -n $3 ]] && reval=$3
++    fi
++    echo $reval
++}
++
++get_footprint()
++{
++    pushd $WSREP_SST_OPT_DATA 1>/dev/null
++    payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }')
++    if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then 
++        # QuickLZ has around 50% compression ratio
++        # When compression/compaction used, the progress is only an approximate.
++        payload=$(( payload*1/2 ))
++    fi
++    popd 1>/dev/null
++    pcmd+=" -s $payload"
++    adjust_progress
++}
++
++adjust_progress()
++{
++    if [[ -n $progress && $progress != '1' ]];then 
++        if [[ -e $progress ]];then 
++            pcmd+=" 2>>$progress"
++        else 
++            pcmd+=" 2>$progress"
++        fi
++    elif [[ -z $progress && -n $rlimit  ]];then 
++            # When rlimit is non-zero
++            pcmd="pv -q"
++    fi 
++
++    if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
++        wsrep_log_info "Rate-limiting SST to $rlimit"
++        pcmd+=" -L \$rlimit"
++    fi
++}
++
++read_cnf()
++{
++    sfmt=$(parse_cnf sst streamfmt "tar")
++    tfmt=$(parse_cnf sst transferfmt "socat")
++    tcert=$(parse_cnf sst tca "")
++    tpem=$(parse_cnf sst tcert "")
++    encrypt=$(parse_cnf sst encrypt 0)
++    sockopt=$(parse_cnf sst sockopt "")
++    progress=$(parse_cnf sst progress "")
++    rebuild=$(parse_cnf sst rebuild 0)
++    ttime=$(parse_cnf sst time 0)
++    incremental=$(parse_cnf sst incremental 0)
++    ealgo=$(parse_cnf xtrabackup encrypt "")
++    ekey=$(parse_cnf xtrabackup encrypt-key "")
++    ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "")
++
++    # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html 
++    if [[ -z $ealgo ]];then
++        ealgo=$(parse_cnf sst encrypt-algo "")
++        ekey=$(parse_cnf sst encrypt-key "")
++        ekeyfile=$(parse_cnf sst encrypt-key-file "")
++    fi
++    rlimit=$(parse_cnf sst rlimit "")
++    uextra=$(parse_cnf sst use_extra 0)
++}
++
++get_stream()
++{
++    if [[ $sfmt == 'xbstream' ]];then 
++        wsrep_log_info "Streaming with xbstream"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            strmcmd="xbstream -x"
++        else
++            strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}"
++        fi
++    else
++        sfmt="tar"
++        wsrep_log_info "Streaming with tar"
++        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
++            strmcmd="tar xfi - --recursive-unlink -h"
++        else
++            strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}"
++        fi
++
++    fi
++}
++
++get_proc()
++{
++    set +e
++    nproc=$(grep -c processor /proc/cpuinfo)
++    [[ -z $nproc || $nproc -eq 0 ]] && nproc=1
++    set -e
++}
++
++sig_joiner_cleanup()
++{
++    wsrep_log_error "Removing $MAGIC_FILE file due to signal"
++    rm -f "$MAGIC_FILE"
++}
++
++cleanup_joiner()
++{
++    # Since this is invoked just after exit NNN
++    local estatus=$?
++    if [[ $estatus -ne 0 ]];then 
++        wsrep_log_error "Cleanup after exit with status:$estatus"
++    fi
++    if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
++        wsrep_log_info "Removing the sst_in_progress file"
++        wsrep_cleanup_progress_file
++    fi
++    if [[ -n $progress && -p $progress ]];then 
++        wsrep_log_info "Cleaning up fifo file $progress"
++        rm $progress
++    fi
++}
++
++check_pid()
++{
++    local pid_file="$1"
++    [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1
++}
++
++cleanup_donor()
++{
++    # Since this is invoked just after exit NNN
++    local estatus=$?
++    if [[ $estatus -ne 0 ]];then 
++        wsrep_log_error "Cleanup after exit with status:$estatus"
++    fi
++
++    if [[ -n $XTRABACKUP_PID ]];then 
++        if check_pid $XTRABACKUP_PID
++        then
++            wsrep_log_error "xtrabackup process is still running. Killing... "
++            kill_xtrabackup
++        fi
++
++        rm -f $XTRABACKUP_PID 
++    fi
++    rm -f ${DATA}/${IST_FILE}
++
++    if [[ -n $progress && -p $progress ]];then 
++        wsrep_log_info "Cleaning up fifo file $progress"
++        rm $progress
++    fi
++}
++
++kill_xtrabackup()
++{
++    local PID=$(cat $XTRABACKUP_PID)
++    [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || :
++    rm -f "$XTRABACKUP_PID"
++}
++
++setup_ports()
++{
++    if [[ "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
++        SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }')
++        REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }')
++        lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }')
++    else
++        SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }')
++    fi
++}
++
++# waits ~10 seconds for nc to open the port and then reports ready
++# (regardless of timeout)
++wait_for_listen()
++{
++    local PORT=$1
++    local ADDR=$2
++    local MODULE=$3
++    for i in {1..50}
++    do
++        ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
++        sleep 0.2
++    done
++    if [[ $incremental -eq 1 ]];then 
++        echo "ready ${ADDR}/${MODULE}/$lsn"
++    else 
++    echo "ready ${ADDR}/${MODULE}"
++    fi
++}
++
++check_extra()
++{
++    local use_socket=1
++    if [[ $uextra -eq 1 ]];then 
++        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then 
++            local eport=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2)
++            if [[ -n $eport ]];then 
++                # Xtrabackup works only locally.
++                # Hence, setting host to 127.0.0.1 unconditionally. 
++                wsrep_log_info "SST through extra_port $eport"
++                INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
++                use_socket=0
++            else 
++                wsrep_log_error "Extra port $eport null, failing"
++                exit 1
++            fi
++        else 
++            wsrep_log_info "Thread pool not set, ignore the option use_extra"
++        fi
++    fi
++    if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
++        INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
++    fi
++}
++
++if [[ ! -x `which innobackupex` ]];then 
++    wsrep_log_error "innobackupex not in path: $PATH"
++    exit 2
++fi
++
++rm -f "${MAGIC_FILE}"
++
++if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then 
++    wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
++    exit 22
++fi
++
++read_cnf
++setup_ports
++get_stream
++get_transfer
++
++INNOEXTRA=""
++INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
++INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log"
++
++if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
++then
++    trap cleanup_donor EXIT
++
++    if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
++    then
++        TMPDIR="${TMPDIR:-/tmp}"
++
++        if [ "${AUTH[0]}" != "(null)" ]; then
++           INNOEXTRA+=" --user=${AUTH[0]}"
++       fi
++
++        if [ ${#AUTH[*]} -eq 2 ]; then
++           INNOEXTRA+=" --password=${AUTH[1]}"
++        elif [ "${AUTH[0]}" != "(null)" ]; then
++           # Empty password, used for testing, debugging etc.
++           INNOEXTRA+=" --password="
++        fi
++
++        get_keys
++        if [[ $encrypt -eq 1 ]];then
++            if [[ -n $ekey ]];then
++                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey "
++            else 
++                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile "
++            fi
++        fi
++
++        if [[ -n $lsn ]];then 
++                INNOEXTRA+=" --incremental --incremental-lsn=$lsn "
++        fi
++
++        check_extra
++
++        wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}"
++
++        if [[ -n $progress ]];then 
++            get_footprint
++            tcmd="$pcmd | $tcmd"
++        elif [[ -n $rlimit ]];then 
++            adjust_progress
++            tcmd="$pcmd | $tcmd"
++        fi
++
++        set +e
++        timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
++        set -e
++
++        if [ ${RC[0]} -ne 0 ]; then
++          wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \
++                          "Check ${DATA}/innobackup.backup.log"
++          exit 22
++        elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then 
++          wsrep_log_error "$tcmd finished with error: ${RC[1]}"
++          exit 22
++        fi
++
++        # innobackupex implicitly writes PID to fixed location in ${TMPDIR}
++        XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid"
++
++
++    else # BYPASS FOR IST
++
++        wsrep_log_info "Bypassing the SST for IST"
++        STATE="${WSREP_SST_OPT_GTID}"
++        echo "continue" # now server can resume updating data
++        echo "${STATE}" > "${MAGIC_FILE}"
++        echo "1" > "${DATA}/${IST_FILE}"
++        get_keys
++        pushd ${DATA} 1>/dev/null
++        set +e
++        if [[ $encrypt -eq 1 ]];then
++            tcmd=" $ecmd | $tcmd"
++        fi
++        timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
++        set -e
++        popd 1>/dev/null
++
++        for ecode in "${RC[@]}";do 
++            if [[ $ecode -ne 0 ]];then 
++                wsrep_log_error "Error while streaming data to joiner node: " \
++                                "exit codes: ${RC[@]}"
++                exit 1
++            fi
++        done
++    fi
++
++    echo "done ${WSREP_SST_OPT_GTID}"
++    wsrep_log_info "Total time on donor: $totime seconds"
++
++elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ]
++then
++    [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
++    touch $SST_PROGRESS_FILE
++
++    if [[ ! -e ${DATA}/ibdata1 ]];then 
++        incremental=0
++    fi
++
++    if [[ $incremental -eq 1 ]];then 
++        wsrep_log_info "Incremental SST enabled"
++        #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF  --basedir=/pxc  --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1)
++        lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ')
++        wsrep_log_info "Recovered LSN: $lsn"
++    fi
++
++    sencrypted=1
++    nthreads=1
++
++    MODULE="xtrabackup_sst"
++
++    # May need xtrabackup_checkpoints later on
++    rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info  ${DATA}/xtrabackup_logfile
++
++    ADDR=${WSREP_SST_OPT_ADDR}
++    if [ -z "${SST_PORT}" ]
++    then
++        SST_PORT=4444
++        ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}"
++    fi
++
++    wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} &
++
++    trap sig_joiner_cleanup HUP PIPE INT TERM
++    trap cleanup_joiner EXIT
++
++    if [[ -n $progress ]];then 
++        adjust_progress
++        tcmd+=" | $pcmd"
++    fi
++
++    if [[ $incremental -eq 1 ]];then 
++        BDATA=$DATA
++        DATA=$(mktemp -d)
++        MAGIC_FILE="${DATA}/${INFO_FILE}"
++    fi
++
++    get_keys
++    set +e
++    if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then
++        strmcmd=" $ecmd | $strmcmd"
++    fi
++
++    pushd ${DATA} 1>/dev/null
++    timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
++    popd 1>/dev/null 
++
++    set -e
++
++    if [[ $sfmt == 'xbstream' ]];then 
++        # Special handling till lp:1193240 is fixed"
++        if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then 
++            wsrep_log_error "Xbstream failed"
++            wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \
++                            "Manual intervention required in that case"
++            exit 32
++        fi
++    fi
++
++    wait %% # join for wait_for_listen thread
++
++    for ecode in "${RC[@]}";do 
++        if [[ $ecode -ne 0 ]];then 
++            wsrep_log_error "Error while getting data from donor node: " \
++                            "exit codes: ${RC[@]}"
++            exit 32
++        fi
++    done
++
++    if [ ! -r "${MAGIC_FILE}" ]
++    then
++        # this message should cause joiner to abort
++        wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'"
++        wsrep_log_info "Contents of datadir" 
++        wsrep_log_info "$(ls -l ${DATA}/**/*)"
++        exit 32
++    fi
++
++    if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null
++    then
++        wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." 
++        exit 32
++    fi
++
++    if [ ! -r "${DATA}/${IST_FILE}" ]
++    then
++        wsrep_log_info "Proceeding with SST"
++        wsrep_log_info "Removing existing ib_logfile files"
++        if [[ $incremental -ne 1 ]];then 
++            rm -f ${DATA}/ib_logfile*
++        else
++            rm -f ${BDATA}/ib_logfile*
++        fi
++
++        get_proc
++
++        # Rebuild indexes for compact backups
++        if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then 
++            wsrep_log_info "Index compaction detected"
++            rebuild=1
++        fi
++
++        if [[ $rebuild -eq 1 ]];then 
++            nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc)
++            wsrep_log_info "Rebuilding during prepare with $nthreads threads"
++            rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads"
++        fi
++
++        if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then
++
++            wsrep_log_info "Compressed qpress files found"
++
++            if [[ ! -x `which qpress` ]];then 
++                wsrep_log_error "qpress not found in path: $PATH"
++                exit 22
++            fi
++
++            if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then
++                count=$(find ${DATA} -type f -name '*.qp' | wc -l)
++                count=$(( count*2 ))
++                if pv --help | grep -q FORMAT;then 
++                    pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'"
++                else 
++                    pvopts="-f -s $count -l -N Decompression"
++                fi
++                pcmd="pv $pvopts"
++                adjust_progress
++                dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d"
++            else 
++                dcmd="xargs -n 2 qpress -T${nproc}d"
++            fi
++
++            wsrep_log_info "Removing existing ibdata1 file"
++            rm -f ${DATA}/ibdata1
++
++            # Decompress the qpress files 
++            wsrep_log_info "Decompression with $nproc threads"
++            timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd"
++            extcode=$?
++
++            if [[ $extcode -eq 0 ]];then
++                wsrep_log_info "Removing qpress files after decompression"
++                find ${DATA} -type f -name '*.qp' -delete 
++                if [[ $? -ne 0 ]];then 
++                    wsrep_log_error "Something went wrong with deletion of qpress files. Investigate"
++                fi
++            else
++                wsrep_log_error "Decompression failed. Exit code: $extcode"
++                exit 22
++            fi
++        fi
++
++        if [[ $incremental -eq 1 ]];then 
++            # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues.
++            INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \
++                --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log"
++        fi
++
++        wsrep_log_info "Preparing the backup at ${DATA}"
++        timeit "Xtrabackup prepare stage" "$INNOAPPLY"
++
++        if [[ $incremental -eq 1 ]];then 
++            wsrep_log_info "Cleaning up ${DATA} after incremental SST"
++            [[ -d ${DATA} ]] && rm -rf ${DATA}
++            DATA=$BDATA
++        fi
++
++        if [ $? -ne 0 ];
++        then
++            wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" 
++            exit 22
++        fi
++    else 
++        wsrep_log_info "${IST_FILE} received from donor: Running IST"
++    fi
++
++    if [[ ! -r ${MAGIC_FILE} ]];then
++        wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable"
++        exit 2
++    fi
++
++    cat "${MAGIC_FILE}" # output UUID:seqno
++    wsrep_log_info "Total time on joiner: $totime seconds"
++fi
++
++exit 0
+diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
+index 3eeb07d..a63d98e 100644
+--- a/sql/CMakeLists.txt
++++ b/sql/CMakeLists.txt
+@@ -13,6 +13,10 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
++IF(WITH_WSREP)
++ SET(WSREP_INCLUDES ${CMAKE_SOURCE_DIR}/wsrep)
++ENDIF()
++
+ INCLUDE_DIRECTORIES(
+   ${CMAKE_SOURCE_DIR}/include 
+   ${CMAKE_SOURCE_DIR}/sql 
+@@ -20,6 +24,7 @@ INCLUDE_DIRECTORIES(
+   ${ZLIB_INCLUDE_DIR}
+   ${SSL_INCLUDE_DIRS}
+   ${CMAKE_BINARY_DIR}/sql
++  ${WSREP_INCLUDES}
+ )
+ SET(GEN_SOURCES
+@@ -171,7 +176,24 @@ SET(SQL_SHARED_SOURCES
+ SET(SQL_EXPORTED_SOURCES ${SQL_SHARED_SOURCES} PARENT_SCOPE)
++IF(WITH_WSREP)
++ SET(WSREP_SOURCES
++   wsrep_check_opts.cc
++   wsrep_hton.cc
++   wsrep_mysqld.cc
++   wsrep_notify.cc
++   wsrep_sst.cc
++   wsrep_utils.cc
++   wsrep_var.cc
++   wsrep_binlog.cc
++   wsrep_applier.cc
++   wsrep_thd.cc
++ )
++ SET(WSREP_LIB wsrep)
++ENDIF()
++
+ SET(SQL_SOURCE
++  ${WSREP_SOURCES}
+   ${GEN_SOURCES}
+   ${MYSYS_LIBWRAP_SOURCE}
+   ${SQL_SHARED_SOURCES}
+@@ -208,6 +230,7 @@ DTRACE_INSTRUMENT(sql)
+ TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} 
+   mysys mysys_ssl dbug strings vio regex   
+   ${LIBWRAP} ${LIBCRYPT} ${LIBDL}
++  ${WSREP_LIB}
+   ${SSL_LIBRARIES})
+ #
+@@ -246,7 +269,6 @@ ADD_LIBRARY(sqlgunitlib
+   )
+ ADD_DEPENDENCIES(sqlgunitlib GenError)
+-
+ IF(WIN32)
+   SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc)
+ ELSE()
+diff --git a/sql/binlog.cc b/sql/binlog.cc
+index d1babfe..bbf87dd 100644
+--- a/sql/binlog.cc
++++ b/sql/binlog.cc
+@@ -60,7 +60,11 @@ static ulonglong limit_unsafe_suppression_start_time= 0;
+ static bool unsafe_warning_suppression_is_activated= false;
+ static int limit_unsafe_warning_count= 0;
++#ifndef WITH_WSREP
+ static handlerton *binlog_hton;
++#else
++handlerton *binlog_hton; // we need it in wsrep_binlog.cc
++#endif
+ bool opt_binlog_order_commits= true;
+ const char *log_bin_index= 0;
+@@ -795,7 +799,9 @@ static binlog_cache_mngr *thd_get_cache_mngr(const THD *thd)
+     If opt_bin_log is not set, binlog_hton->slot == -1 and hence
+     thd_get_ha_data(thd, hton) segfaults.
+   */
++#ifndef WITH_WSREP
+   DBUG_ASSERT(opt_bin_log);
++#endif
+   return (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
+ }
+@@ -881,7 +887,11 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos)
+   DBUG_ENTER("binlog_trans_log_savepos");
+   DBUG_ASSERT(pos != NULL);
+   binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
++#ifdef WITH_WSREP
++  DBUG_ASSERT((WSREP_EMULATE_BINLOG(thd)) || mysql_bin_log.is_open());
++#else
+   DBUG_ASSERT(mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
+   *pos= cache_mngr->trx_cache.get_byte_position();
+   DBUG_PRINT("return", ("position: %lu", (ulong) *pos));
+   DBUG_VOID_RETURN;
+@@ -897,7 +907,16 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos)
+ static int binlog_init(void *p)
+ {
+   binlog_hton= (handlerton *)p;
++#ifdef WITH_WSREP
++  if (WSREP_ON)
++    binlog_hton->state= SHOW_OPTION_YES;
++  else
++  {
++#endif /* WITH_WSREP */
+   binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
++#ifdef WITH_WSREP
++  }
++#endif /* WITH_WSREP */
+   binlog_hton->db_type=DB_TYPE_BINLOG;
+   binlog_hton->savepoint_offset= sizeof(my_off_t);
+   binlog_hton->close_connection= binlog_close_connection;
+@@ -912,10 +931,30 @@ static int binlog_init(void *p)
+   return 0;
+ }
++#ifdef WITH_WSREP
++#include "wsrep_binlog.h"
++#endif /* WITH_WSREP */
+ static int binlog_close_connection(handlerton *hton, THD *thd)
+ {
+   DBUG_ENTER("binlog_close_connection");
+   binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
++#ifdef WITH_WSREP
++  if (!cache_mngr->is_binlog_empty()) {
++    IO_CACHE* cache= get_trans_log(thd);
++    uchar *buf;
++    size_t len=0;
++    wsrep_write_cache_buf(cache, &buf, &len);
++    WSREP_WARN("binlog trx cache not empty (%lu bytes) @ connection close %lu",
++               len, thd->thread_id);
++    if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
++
++    cache = cache_mngr->get_binlog_cache_log(false);
++    wsrep_write_cache_buf(cache, &buf, &len);
++    WSREP_WARN("binlog stmt cache not empty (%lu bytes) @ connection close %lu",
++               len, thd->thread_id);
++    if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
++  }
++#endif /* WITH_WSREP */
+   DBUG_ASSERT(cache_mngr->is_binlog_empty());
+   DBUG_ASSERT(cache_mngr->trx_cache.is_group_cache_empty() &&
+               cache_mngr->stmt_cache.is_group_cache_empty());
+@@ -1666,7 +1705,11 @@ int MYSQL_BIN_LOG::rollback(THD *thd, bool all)
+   if (error == 0 && stuff_logged)
+     error= ordered_commit(thd, all, /* skip_commit */ true);
++#ifdef WITH_WSREP
++  if (!WSREP_EMULATE_BINLOG(thd) && check_write_error(thd))
++#else
+   if (check_write_error(thd))
++#endif
+   {
+     /*
+       "all == true" means that a "rollback statement" triggered the error and
+@@ -4771,6 +4814,43 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time, bool auto_purge)
+                         no_of_log_files_purged, no_of_log_files_to_purge);
+   }
++  if (log_is_active)
++  {
++    if(!auto_purge)
++      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
++                          ER_WARN_PURGE_LOG_IS_ACTIVE,
++                          ER(ER_WARN_PURGE_LOG_IS_ACTIVE),
++                          log_info.log_file_name);
++
++  }
++
++  if (log_is_in_use)
++  {
++    int no_of_log_files_to_purge= no_of_log_files_purged+1;
++    while (strcmp(log_file_name, log_info.log_file_name))
++    {
++      if (mysql_file_stat(m_key_file_log, log_info.log_file_name,
++                          &stat_area, MYF(0)))
++      {
++        if (stat_area.st_mtime < purge_time)
++          no_of_log_files_to_purge++;
++        else
++          break;
++      }
++      if (find_next_log(&log_info, false/*need_lock_index=false*/))
++      {
++        no_of_log_files_to_purge++;
++        break;
++      }
++    }
++
++    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
++                        ER_WARN_PURGE_LOG_IN_USE,
++                        ER(ER_WARN_PURGE_LOG_IN_USE),
++                        copy_log_in_use, no_of_threads_locking_log,
++                        no_of_log_files_purged, no_of_log_files_to_purge);
++  }
++
+   error= (to_log[0] ? purge_logs(to_log, true,
+                                  false/*need_lock_index=false*/,
+                                  true/*need_update_threads=true*/,
+@@ -5190,7 +5270,11 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
+                                                 bool is_transactional)
+ {
+   DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
++#ifdef WITH_WSREP
++  DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open());
++#else
+   DBUG_ASSERT(mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
+   DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
+   int error= 0;
+@@ -5265,7 +5349,13 @@ bool MYSQL_BIN_LOG::write_event(Log_event *event_info)
+      mostly called if is_open() *was* true a few instructions before, but it
+      could have changed since.
+   */
++#ifdef WITH_WSREP
++  /* applier and replayer can skip writing binlog events */
++  if ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || 
++      is_open())
++#else
+   if (likely(is_open()))
++#endif
+   {
+ #ifdef HAVE_REPLICATION
+     /*
+@@ -5412,6 +5502,15 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge)
+ {
+   int error= 0;
+   DBUG_ENTER("MYSQL_BIN_LOG::rotate");
++#ifdef WITH_WSREP
++  if (WSREP_ON && wsrep_to_isolation)
++    {
++      *check_purge= false;
++      WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", 
++                wsrep_to_isolation);
++      DBUG_RETURN(0);
++    }
++#endif
+   DBUG_ASSERT(!is_relay_log);
+   mysql_mutex_assert_owner(&LOCK_log);
+@@ -5898,6 +5997,9 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log,
+ bool MYSQL_BIN_LOG::write_cache(THD *thd, binlog_cache_data *cache_data)
+ {
+   DBUG_ENTER("MYSQL_BIN_LOG::write_cache(THD *, binlog_cache_data *, bool)");
++#ifdef WITH_WSREP
++  if (WSREP_EMULATE_BINLOG(thd)) DBUG_RETURN(0);
++#endif /* WITH_WSREP */
+   IO_CACHE *cache= &cache_data->cache_log;
+   bool incident= cache_data->has_incident();
+@@ -6353,7 +6455,13 @@ TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all)
+   DBUG_ENTER("MYSQL_BIN_LOG::commit");
+   binlog_cache_mngr *cache_mngr= thd_get_cache_mngr(thd);
++#ifdef WITH_WSREP
++  my_xid xid= (wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid) ?
++               wsrep_xid_seqno(&thd->transaction.xid_state.xid) :
++               thd->transaction.xid_state.xid.get_my_xid());
++#else
+   my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
++#endif /* WITH_WSREP */
+   int error= RESULT_SUCCESS;
+   bool stuff_logged= false;
+@@ -6939,6 +7047,27 @@ int MYSQL_BIN_LOG::ordered_commit(THD *thd, bool all, bool skip_commit)
+   my_off_t total_bytes= 0;
+   bool do_rotate= false;
++#ifdef WITH_WSREP
++  if (WSREP_EMULATE_BINLOG(thd))
++  {
++    /*
++      Skip group commit, just do storage engine commit.
++    */
++    int rcode = ha_commit_low(thd, all);
++
++    /* if there is myisam statement inside innodb transaction, we may
++       have events in stmt cache
++    */
++    binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
++    if(!cache_mngr->stmt_cache.is_binlog_empty())
++    {
++      WSREP_DEBUG("stmt transaction inside MST, SQL: %s", thd->query());
++      cache_mngr->stmt_cache.reset();
++    }
++    DBUG_RETURN(rcode);
++  }
++#endif /* WITH_WSREP */
++
+   /*
+     These values are used while flushing a transaction, so clear
+     everything.
+@@ -7143,6 +7272,24 @@ int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle,
+   */
+   bool in_transaction= FALSE;
++#ifdef WITH_WSREP
++  /*
++    Read current wsrep position from storage engines to have consistent
++    end position for binlog scan.
++  */
++  XID xid;
++  memset(&xid, 0, sizeof(xid));
++  xid.formatID= -1;
++  wsrep_get_SE_checkpoint(&xid);
++  char uuid_str[40];
++  wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, sizeof(uuid_str));
++  WSREP_INFO("Binlog recovery, found wsrep position %s:%lld", uuid_str,
++             (long long)wsrep_xid_seqno(&xid));
++  const wsrep_seqno_t last_xid_seqno= wsrep_xid_seqno(&xid);
++  wsrep_seqno_t cur_xid_seqno=WSREP_SEQNO_UNDEFINED;
++#endif /* WITH_WSREP */
++
++
+   if (! fdle->is_valid() ||
+       my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
+                    sizeof(my_xid), 0, 0, MYF(0)))
+@@ -7151,7 +7298,12 @@ int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle,
+   init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
+   while ((ev= Log_event::read_log_event(log, 0, fdle, TRUE))
+-         && ev->is_valid())
++         && ev->is_valid()
++#ifdef WITH_WSREP
++         && (last_xid_seqno == WSREP_SEQNO_UNDEFINED ||
++             last_xid_seqno != cur_xid_seqno)
++#endif
++      )
+   {
+     if (ev->get_type_code() == QUERY_EVENT &&
+         !strcmp(((Query_log_event*)ev)->query, "BEGIN"))
+@@ -7172,6 +7324,9 @@ int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle,
+                                       sizeof(xev->xid));
+       if (!x || my_hash_insert(&xids, x))
+         goto err2;
++#ifdef WITH_WSREP
++      cur_xid_seqno= xev->xid;
++#endif /* WITH_WSREP */
+     }
+     /*
+@@ -7216,6 +7371,11 @@ int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle,
+     delete ev;
+   }
++#ifdef WITH_WSREP
++  WSREP_INFO("Binlog recovery scan stopped at Xid event %lld",
++             (long long)cur_xid_seqno);
++#endif /* WITH_WSREP */
++
+   if (ha_recover(&xids))
+     goto err2;
+@@ -7240,7 +7400,9 @@ Group_cache *THD::get_group_cache(bool is_transactional)
+   // If opt_bin_log==0, it is not safe to call thd_get_cache_mngr
+   // because binlog_hton has not been completely set up.
++#ifndef WITH_WSREP
+   DBUG_ASSERT(opt_bin_log);
++#endif
+   binlog_cache_mngr *cache_mngr= thd_get_cache_mngr(this);
+   // cache_mngr is NULL until we call thd->binlog_setup_trx_data, so
+@@ -7433,7 +7595,12 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
+                        table->s->table_map_id.id()));
+   /* Pre-conditions */
++#ifdef WITH_WSREP
++  DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
++            (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()));
++#else
+   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
+   DBUG_ASSERT(table->s->table_map_id.is_valid());
+   Table_map_log_event
+@@ -7721,9 +7888,16 @@ int THD::decide_logging_format(TABLE_LIST *tables)
+     binlogging is off, or if the statement is filtered out from the
+     binlog by filtering rules.
+   */
++#ifdef WITH_WSREP
++  if ((WSREP_EMULATE_BINLOG(this) || 
++       (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG))) &&
++      !(WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT    &&
++      !binlog_filter->db_ok(db)))
++#else
+   if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
+       !(variables.binlog_format == BINLOG_FORMAT_STMT &&
+         !binlog_filter->db_ok(db)))
++#endif /* WITH_WSREP */
+   {
+     /*
+       Compute one bit field with the union of all the engine
+@@ -7967,7 +8141,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
+         */
+         my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
+       }
+-      else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
++      else if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW &&
+                sqlcom_can_generate_row_events(this))
+       {
+         /*
+@@ -7996,8 +8170,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
+     else
+     {
+       /* binlog_format = STATEMENT */
+-      if (variables.binlog_format == BINLOG_FORMAT_STMT)
+-      {
++      if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT)
++       {
+         if (lex->is_stmt_row_injection())
+         {
+           /*
+@@ -8013,7 +8187,14 @@ int THD::decide_logging_format(TABLE_LIST *tables)
+             5. Error: Cannot modify table that uses a storage engine
+                limited to row-logging when binlog_format = STATEMENT
+           */
++#ifdef WITH_WSREP
++          if (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE)
++          {
++#endif /* WITH_WSREP */
+           my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
++#ifdef WITH_WSREP
++          }
++#endif /* WITH_WSREP */
+         }
+         else if (is_write && (unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
+         {
+@@ -8159,7 +8340,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
+                         "and binlog_filter->db_ok(db) = %d",
+                         mysql_bin_log.is_open(),
+                         (variables.option_bits & OPTION_BIN_LOG),
+-                        variables.binlog_format,
++                        WSREP_BINLOG_FORMAT(variables.binlog_format),
+                         binlog_filter->db_ok(db)));
+ #endif
+@@ -8469,7 +8650,12 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
+                           uchar const *record,
+                           const uchar* extra_row_info)
+ { 
++#ifdef WITH_WSREP
++  DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
++            ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
++#else
+   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
+   /*
+     Pack records into format for transfer. We are allocating more
+@@ -8499,7 +8685,13 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
+                            const uchar *after_record,
+                            const uchar* extra_row_info)
+ { 
++#ifdef WITH_WSREP
++  DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
++            ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
++#else
+   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
++
+   int error= 0;
+   /**
+@@ -8565,7 +8757,13 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
+                            uchar const *record,
+                            const uchar* extra_row_info)
+ { 
++#ifdef WITH_WSREP
++  DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
++            ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
++#else
+   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
++
+   int error= 0;
+   /**
+@@ -8683,7 +8881,11 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
+     mode: it might be the case that we left row-based mode before
+     flushing anything (e.g., if we have explicitly locked tables).
+    */
+-  if (!mysql_bin_log.is_open())
++#ifdef WITH_WSREP
++  if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()))
++#else
++ if (!mysql_bin_log.is_open())
++#endif /* WITH_WSREP */
+     DBUG_RETURN(0);
+   /*
+@@ -8952,7 +9154,21 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
+   DBUG_ENTER("THD::binlog_query");
+   DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
+                        show_query_type(qtype), query_arg));
++#ifdef WITH_WSREP
++  DBUG_ASSERT(query_arg && (WSREP_EMULATE_BINLOG(this)
++                          || mysql_bin_log.is_open()));
++#else
+   DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
++#endif /* WITH_WSREP */
++
++  if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET)
++  {
++    /*
++      The current statement is to be ignored, and not written to
++      the binlog. Do not call issue_unsafe_warnings().
++    */
++    DBUG_RETURN(0);
++  }
+   if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET)
+   {
+@@ -9056,6 +9272,72 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
+ }
+ #endif /* !defined(MYSQL_CLIENT) */
++#ifdef WITH_WSREP
++IO_CACHE * get_trans_log(THD * thd)
++{
++  binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
++  if (cache_mngr)
++  {
++    return cache_mngr->get_binlog_cache_log(true);
++  }
++  else
++  {
++    WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id);
++    return NULL;
++  }
++}
++
++bool wsrep_trans_cache_is_empty(THD *thd)
++{
++  binlog_cache_mngr *const cache_mngr=
++      (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
++  return (!cache_mngr || cache_mngr->trx_cache.is_binlog_empty());
++}
++
++void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end)
++{
++  thd->binlog_flush_pending_rows_event(stmt_end);
++}
++void thd_binlog_trx_reset(THD * thd)
++{
++  /*
++    todo: fix autocommit select to not call the caller
++  */
++  if (thd_get_ha_data(thd, binlog_hton) != NULL)
++  {
++    binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
++    if (cache_mngr) 
++    {
++      cache_mngr->trx_cache.reset();
++      if (!cache_mngr->stmt_cache.is_binlog_empty())
++      {
++      WSREP_DEBUG("pending events in stmt cache, sql: %s", thd->query());
++      cache_mngr->stmt_cache.reset();
++      }
++    }
++  }
++  thd->clear_binlog_table_maps();
++}
++
++TC_LOG::enum_result wsrep_thd_binlog_commit(THD* thd, bool all)
++{
++  /* applier and replayer can skip binlog commit */
++  if (WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV))
++    return mysql_bin_log.commit(thd, all);
++  else
++    return (ha_commit_low(thd, all) ?
++            TC_LOG::RESULT_ABORTED : TC_LOG::RESULT_SUCCESS);
++}
++
++int wsrep_thd_binlog_rollback(THD* thd, bool all)
++{
++  /* applier and replayer can skip binlog rollback */
++  if (WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV))
++    return mysql_bin_log.rollback(thd, all);
++  else
++    return ha_rollback_low(thd, all);
++}
++#endif /* WITH_WSREP */
+ struct st_mysql_storage_engine binlog_storage_engine=
+ { MYSQL_HANDLERTON_INTERFACE_VERSION };
+diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
+index 13a7691..139f0dc 100644
+--- a/sql/event_data_objects.cc
++++ b/sql/event_data_objects.cc
+@@ -1477,8 +1477,25 @@ end:
+       bool save_tx_read_only= thd->tx_read_only;
+       thd->tx_read_only= false;
++#ifdef WITH_WSREP
++      if (WSREP(thd)) {
++          // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX));
++          // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack.
++          LEX lex;
++          LEX* saved = thd->lex;
++          lex.sql_command = SQLCOM_DROP_EVENT;
++          thd->lex = &lex;
++          WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
++          thd->lex = saved;
++      }
++#endif
++     
+       ret= Events::drop_event(thd, dbname, name, FALSE);
++#ifdef WITH_WSREP
++      WSREP_TO_ISOLATION_END;
++  error:
++#endif      
+       thd->tx_read_only= save_tx_read_only;
+       thd->security_ctx->master_access= saved_master_access;
+     }
+diff --git a/sql/events.cc b/sql/events.cc
+index ff87dd4..25e2e04 100644
+--- a/sql/events.cc
++++ b/sql/events.cc
+@@ -1139,7 +1139,20 @@ Events::load_events_from_db(THD *thd)
+       delete et;
+       goto end;
+     }
+-
++#ifdef WITH_WSREP
++    // when SST from master node who initials event, the event status is ENABLED
++    // this is problematic because there are two nodes with same events and both enabled.
++    if (et->originator != thd->server_id)
++    {
++        store_record(table, record[1]);
++        table->field[ET_FIELD_STATUS]->
++                store((longlong) Event_parse_data::SLAVESIDE_DISABLED,
++                      TRUE);
++        (void) table->file->ha_update_row(table->record[1], table->record[0]);
++        delete et;
++        continue;
++    }
++#endif
+     /**
+       Since the Event_queue_element object could be deleted inside
+       Event_queue::create_event we should save the value of dropped flag
+@@ -1183,7 +1196,46 @@ end:
+   close_mysql_tables(thd);
+   DBUG_RETURN(ret);
+ }
++#ifdef WITH_WSREP
++int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len)
++{
++  String log_query;
++  if (create_query_string(thd, &log_query))
++  {
++    WSREP_WARN("events create string failed: %s", thd->query());
++    return 1;
++  }
++  return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
++}
++static int
++wsrep_alter_query_string(THD *thd, String *buf)
++{
++  /* Append the "ALTER" part of the query */
++  if (buf->append(STRING_WITH_LEN("ALTER ")))
++    return 1;
++  /* Append definer */
++  append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
++  /* Append the left part of thd->query after event name part */
++  if (buf->append(thd->lex->stmt_definition_begin,
++                  thd->lex->stmt_definition_end -
++                  thd->lex->stmt_definition_begin))
++    return 1;
++ 
++  return 0;
++}
++int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len)
++{
++  String log_query;
++
++  if (wsrep_alter_query_string(thd, &log_query))
++  {
++    WSREP_WARN("events alter string failed: %s", thd->query());
++    return 1;
++  }
++  return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
++}
++#endif /* WITH_WSREP */
+ /**
+   @} (End of group Event_Scheduler)
+ */
+diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
+index 26172ca..f92eb5d 100644
+--- a/sql/ha_partition.cc
++++ b/sql/ha_partition.cc
+@@ -411,7 +411,13 @@ const char *ha_partition::table_type() const
+   // we can do this since we only support a single engine type
+   return m_file[0]->table_type(); 
+ }
+-
++#ifdef WITH_WSREP
++int ha_partition::wsrep_db_type() const
++{ 
++  // we can do this since we only support a single engine type
++  return ha_legacy_type(m_file[0]->ht); 
++}
++#endif /* WITH_WSREP */
+ /*
+   Destructor method
+diff --git a/sql/ha_partition.h b/sql/ha_partition.h
+index 6b20de0..acdfeb9 100644
+--- a/sql/ha_partition.h
++++ b/sql/ha_partition.h
+@@ -1244,6 +1244,9 @@ public:
+     -------------------------------------------------------------------------
+     virtual void append_create_info(String *packet)
+   */
++#ifdef WITH_WSREP
++    virtual int wsrep_db_type() const;
++#endif /* WITH_WSREP */
+ };
+ #endif /* HA_PARTITION_INCLUDED */
+diff --git a/sql/handler.cc b/sql/handler.cc
+index f91c04c..e39e0d8 100644
+--- a/sql/handler.cc
++++ b/sql/handler.cc
+@@ -60,7 +60,9 @@ inline double log2(double x)
+   return (log(x) / M_LN2);
+ }
+ #endif
+-
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif
+ /*
+   While we have legacy_db_type, we have this array to
+   check for dups and to find handlerton from legacy_db_type.
+@@ -1219,10 +1221,27 @@ int ha_prepare(THD *thd)
+       {
+         if ((err= ht->prepare(ht, thd, all)))
+         {
++#ifdef WITH_WSREP
++          if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP)
++          {
++          error= 1;
++          /* avoid sending error, if we need to replay */
++            if (thd->wsrep_conflict_state!= MUST_REPLAY)
++            {
++              my_error(ER_LOCK_DEADLOCK, MYF(0), err);
++            }
++          }
++          else
++          {
++            /* not wsrep hton, bail to native mysql behavior */
++#endif
+           my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+           ha_rollback_trans(thd, all);
+           error=1;
+           break;
++#ifdef WITH_WSREP
++          }
++#endif
+         }
+       }
+       else
+@@ -1233,7 +1252,6 @@ int ha_prepare(THD *thd)
+       }
+     }
+   }
+-
+   DBUG_RETURN(error);
+ }
+@@ -1408,7 +1426,12 @@ int ha_commit_trans(THD *thd, bool all, bool ignore_global_read_lock)
+                        MDL_EXPLICIT);
+       DBUG_PRINT("debug", ("Acquire MDL commit lock"));
++#ifdef WITH_WSREP
++      if (!WSREP(thd) &&
++          thd->mdl_context.acquire_lock(&mdl_request,
++#else
+       if (thd->mdl_context.acquire_lock(&mdl_request,
++#endif /* WITH_WSREP */
+                                         thd->variables.lock_wait_timeout))
+       {
+         ha_rollback_trans(thd, all);
+@@ -1482,7 +1505,19 @@ int ha_commit_low(THD *thd, bool all, bool run_after_commit)
+   int error=0;
+   THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+   Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
++
+   DBUG_ENTER("ha_commit_low");
++#ifdef WITH_WSREP
++#ifdef WSREP_PROC_INFO
++  char info[64]= { 0, };
++  snprintf (info, sizeof(info) - 1, "ha_commit_one_phase(%lld)",
++            (long long)wsrep_thd_trx_seqno(thd));
++#else
++  const char info[]="ha_commit_one_phase()";
++#endif /* WSREP_PROC_INFO */
++  char* tmp_info= NULL;
++  if (WSREP(thd)) tmp_info= (char *)thd_proc_info(thd, info);
++#endif /* WITH_WSREP */
+   if (ha_info)
+   {
+@@ -1513,6 +1548,9 @@ int ha_commit_low(THD *thd, bool all, bool run_after_commit)
+   /* Free resources and perform other cleanup even for 'empty' transactions. */
+   if (all)
+     thd->transaction.cleanup();
++#ifdef WITH_WSREP
++  if (WSREP(thd)) thd_proc_info(thd, tmp_info);
++#endif /* WITH_WSREP */
+   /*
+     When the transaction has been committed, we clear the commit_low
+     flag. This allow other parts of the system to check if commit_low
+@@ -1798,7 +1836,13 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
+                             got, ha_resolve_storage_engine_name(hton));
+       for (int i=0; i < got; i ++)
+       {
++#ifdef WITH_WSREP
++        my_xid x=(wsrep_is_wsrep_xid(&info->list[i]) ?
++                  wsrep_xid_seqno(&info->list[i]) :
++                  info->list[i].get_my_xid());
++#else
+         my_xid x=info->list[i].get_my_xid();
++#endif /* WITH_WSREP */
+         if (!x) // not "mine" - that is generated by external TM
+         {
+ #ifndef DBUG_OFF
+@@ -1867,7 +1911,9 @@ int ha_recover(HASH *commit_list)
+     for now, only InnoDB supports 2pc. It means we can always safely
+     rollback all pending transactions, without risking inconsistent data
+   */
++#ifndef WITH_WSREP
+   DBUG_ASSERT(total_ha_2pc == (ulong) opt_bin_log+1); // only InnoDB and binlog
++#endif
+   tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
+   info.dry_run=FALSE;
+ #endif
+@@ -2103,8 +2149,35 @@ int ha_prepare_low(THD *thd, bool all)
+         continue;
+       if ((err= ht->prepare(ht, thd, all)))
+       {
++#ifdef WITH_WSREP
++      if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP)
++        {
++        error= 1;
++        switch (err)
++          {
++        case WSREP_TRX_SIZE_EXCEEDED:
++          /* give user size exeeded erro from wsrep_api.h */
++          my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED);
++          break;
++        case WSREP_TRX_CERT_FAIL:
++        case WSREP_TRX_ERROR:
++          /* avoid sending error, if we need to replay */
++          if (thd->wsrep_conflict_state!= MUST_REPLAY)
++            {
++            my_error(ER_LOCK_DEADLOCK, MYF(0), err);
++          }
++        }
++      }
++
++        else
++        {
++          /* not wsrep hton, bail to native mysql behavior */
++#endif
+         my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+         error= 1;
++#ifdef WITH_WSREP
++        }
++#endif
+       }
+       status_var_increment(thd->status_var.ha_prepare_count);
+     }
+@@ -3336,7 +3409,12 @@ int handler::update_auto_increment()
+                                           variables->auto_increment_increment);
+     auto_inc_intervals_count++;
+     /* Row-based replication does not need to store intervals in binlog */
++#ifdef WITH_WSREP
++    if (((WSREP_EMULATE_BINLOG(thd)) || mysql_bin_log.is_open()) &&
++      !thd->is_current_stmt_binlog_format_row())
++#else
+     if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row())
++#endif /* WITH_WSREP */
+         thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
+                                                               auto_inc_interval_for_cur_row.values(),
+                                                               variables->auto_increment_increment);
+@@ -4621,7 +4699,9 @@ int ha_enable_transaction(THD *thd, bool on)
+   int error=0;
+   DBUG_ENTER("ha_enable_transaction");
+   DBUG_PRINT("enter", ("on: %d", (int) on));
+-
++#ifdef WITH_WSREP
++  if (thd->wsrep_applier) DBUG_RETURN(0);
++#endif
+   if ((thd->transaction.flags.enabled= on))
+   {
+     /*
+@@ -7017,7 +7097,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
+   return (thd->is_current_stmt_binlog_format_row() &&
+           table->s->cached_row_logging_check &&
+           (thd->variables.option_bits & OPTION_BIN_LOG) &&
++#ifdef WITH_WSREP
++        /* applier and replayer should not binlog */
++          ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) ||
++           mysql_bin_log.is_open()));
++#else
+           mysql_bin_log.is_open());
++#endif
+ }
+@@ -7118,6 +7204,17 @@ int binlog_log_row(TABLE* table,
+   bool error= 0;
+   THD *const thd= table->in_use;
++#ifdef WITH_WSREP
++  /* only InnoDB tables will be replicated through binlog emulation */
++  if (WSREP_EMULATE_BINLOG(thd)                          && 
++      table->file->ht->db_type != DB_TYPE_INNODB         &&
++      !(table->file->ht->db_type == DB_TYPE_PARTITION_DB && 
++      (((ha_partition*)(table->file))->wsrep_db_type() == DB_TYPE_INNODB)))
++      //      !strcmp(table->file->table_type(), "InnoDB"))
++  {
++    return 0;
++  } 
++#endif /* WITH_WSREP */
+   if (check_table_binlog_row_based(thd, table))
+   {
+     DBUG_DUMP("read_set 10", (uchar*) table->read_set->bitmap,
+@@ -7438,6 +7535,64 @@ void signal_log_not_needed(struct handlerton, char *log_file)
+   DBUG_VOID_RETURN;
+ }
++#ifdef WITH_WSREP
++/**
++  @details
++  This function makes the storage engine to force the victim transaction
++  to abort. Currently, only innodb has this functionality, but any SE
++  implementing the wsrep API should provide this service to support
++  multi-master operation.
++
++  @param bf_thd       brute force THD asking for the abort
++  @param victim_thd   victim THD to be aborted
++
++  @return
++    always 0
++*/
++
++int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
++{
++  DBUG_ENTER("ha_wsrep_abort_transaction");
++  if (!WSREP(bf_thd) &&  
++      !(wsrep_OSU_method_options == WSREP_OSU_RSU &&
++        bf_thd->wsrep_exec_mode == TOTAL_ORDER)) {
++    DBUG_RETURN(0);
++  }
++
++  handlerton *hton= installed_htons[DB_TYPE_INNODB];
++  if (hton && hton->wsrep_abort_transaction)
++  {
++    hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal);
++  } 
++  else 
++  {
++    WSREP_WARN("cannot abort InnoDB transaction");
++  }
++
++  DBUG_RETURN(0);
++}
++
++void ha_wsrep_fake_trx_id(THD *thd)
++{
++  DBUG_ENTER("ha_wsrep_fake_trx_id");
++  if (!WSREP(thd)) 
++  {
++    DBUG_VOID_RETURN;
++  }
++
++  handlerton *hton= installed_htons[DB_TYPE_INNODB];
++  if (hton && hton->wsrep_fake_trx_id)
++  {
++    hton->wsrep_fake_trx_id(hton, thd);
++  } 
++  else 
++  {
++    WSREP_WARN("cannot get get fake InnoDB transaction ID");
++  }
++
++  DBUG_VOID_RETURN;
++}
++#endif /* WITH_WSREP */
+ #ifdef TRANS_LOG_MGM_EXAMPLE_CODE
+ /*
+   Example of transaction log management functions based on assumption that logs
+diff --git a/sql/handler.h b/sql/handler.h
+index 3d7d4fa..702b291 100644
+--- a/sql/handler.h
++++ b/sql/handler.h
+@@ -392,6 +392,7 @@ enum legacy_db_type
+   DB_TYPE_MARIA,
+   /** Performance schema engine. */
+   DB_TYPE_PERFORMANCE_SCHEMA,
++  DB_TYPE_WSREP,
+   DB_TYPE_FIRST_DYNAMIC=42,
+   DB_TYPE_DEFAULT=127 // Must be last
+ };
+@@ -924,6 +925,11 @@ struct handlerton
+                      const char *wild, bool dir, List<LEX_STRING> *files);
+    int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
+                                  const char *name);
++   int (*wsrep_abort_transaction)(handlerton *hton, THD *bf_thd, 
++                                THD *victim_thd, my_bool signal);
++   int (*wsrep_set_checkpoint)(handlerton *hton, const XID* xid);
++   int (*wsrep_get_checkpoint)(handlerton *hton, XID* xid);
++   void (*wsrep_fake_trx_id)(handlerton *hton, THD *thd);
+    int (*make_pushed_join)(handlerton *hton, THD* thd, 
+                            const AQP::Join_plan* plan);
+@@ -3332,6 +3338,9 @@ private:
+ extern const char *ha_row_type[];
+ extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[];
+ extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[];
++#ifdef WITH_WSREP
++extern MYSQL_PLUGIN_IMPORT const char *wsrep_binlog_format_names[];
++#endif /* WITH_WSREP */
+ extern TYPELIB tx_isolation_typelib;
+ extern const char *myisam_stats_method_names[];
+ extern ulong total_ha, total_ha_2pc;
+@@ -3440,6 +3449,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
+ bool ha_rollback_to_savepoint_can_release_mdl(THD *thd);
+ int ha_savepoint(THD *thd, SAVEPOINT *sv);
+ int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
++#ifdef WITH_WSREP
++int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal);
++void ha_wsrep_fake_trx_id(THD *thd);
++#endif /* WITH_WSREP */
+ /* Build pushed joins in handlers implementing this feature */
+ int ha_make_pushed_joins(THD *thd, const AQP::Join_plan* plan);
+@@ -3471,6 +3484,12 @@ void ha_binlog_wait(THD *thd);
+ #define ha_binlog_log_query(a,b,c,d,e,f,g) do {} while (0)
+ #define ha_binlog_wait(a) do {} while (0)
+ #endif
++#ifdef WITH_WSREP
++void wsrep_brute_force_aborts();
++#endif
++
++/* It is required by basic binlog features on both MySQL server and libmysqld */
++int ha_binlog_end(THD *thd);
+ /* It is required by basic binlog features on both MySQL server and libmysqld */
+ int ha_binlog_end(THD *thd);
+diff --git a/sql/item_func.cc b/sql/item_func.cc
+index e5ff0b8..9030a02 100644
+--- a/sql/item_func.cc
++++ b/sql/item_func.cc
+@@ -2618,7 +2618,19 @@ void Item_func_rand::seed_random(Item *arg)
+     TODO: do not do reinit 'rand' for every execute of PS/SP if
+     args[0] is a constant.
+   */
++#ifdef WITH_WSREP
++  uint32 tmp;
++  if (WSREP(current_thd))
++  {
++    if (current_thd->wsrep_exec_mode==REPL_RECV) 
++      tmp= current_thd->wsrep_rand;
++    else
++      tmp= current_thd->wsrep_rand= (uint32) arg->val_int();
++  } else
++         tmp= (uint32) arg->val_int();
++#else
+   uint32 tmp= (uint32) arg->val_int();
++#endif
+   randominit(rand, (uint32) (tmp*0x10001L+55555555L),
+              (uint32) (tmp*0x10000001L));
+ }
+diff --git a/sql/lock.cc b/sql/lock.cc
+index 43f2773..e3f613d 100644
+--- a/sql/lock.cc
++++ b/sql/lock.cc
+@@ -83,6 +83,10 @@
+ #include <hash.h>
+ #include <assert.h>
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif /* WITH_WSREP */
++
+ /**
+   @defgroup Locking Locking
+   @{
+@@ -314,6 +318,10 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
+   /* Copy the lock data array. thr_multi_lock() reorders its contents. */
+   memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
+          sql_lock->lock_count * sizeof(*sql_lock->locks));
++#ifdef WITH_WSREP
++  //thd->main_lock_id.info->in_lock_tables= thd->in_lock_tables;
++    thd->lock_info.in_lock_tables= thd->in_lock_tables;
++#endif    /* Lock on the copied half of the lock data array. */
+   /* Lock on the copied half of the lock data array. */
+   rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
+                                                    sql_lock->lock_count,
+@@ -1014,11 +1022,15 @@ void Global_read_lock::unlock_global_read_lock(THD *thd)
+   {
+     thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
+     m_mdl_blocks_commits_lock= NULL;
++#ifdef WITH_WSREP
++    wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
++    wsrep->resume(wsrep);
++#endif /* WITH_WSREP */
+   }
+   thd->mdl_context.release_lock(m_mdl_global_shared_lock);
+   m_mdl_global_shared_lock= NULL;
+   m_state= GRL_NONE;
+-
++ 
+   DBUG_VOID_RETURN;
+ }
+@@ -1046,6 +1058,20 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
+     If we didn't succeed lock_global_read_lock(), or if we already suceeded
+     make_global_read_lock_block_commit(), do nothing.
+   */
++
++#ifdef WITH_WSREP
++  if (m_mdl_blocks_commits_lock)
++  {
++    WSREP_DEBUG("GRL was in block commit mode when entering "
++              "make_global_read_lock_block_commit");
++    thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
++    m_mdl_blocks_commits_lock= NULL;
++    wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
++    wsrep->resume(wsrep);
++    m_state= GRL_ACQUIRED;
++  }
++#endif /* WITH_WSREP */
++
+   if (m_state != GRL_ACQUIRED)
+     DBUG_RETURN(0);
+@@ -1058,6 +1084,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
+   m_mdl_blocks_commits_lock= mdl_request.ticket;
+   m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
++#ifdef WITH_WSREP
++  long long ret = wsrep->pause(wsrep);
++  if (ret >= 0)
++  {
++    wsrep_locked_seqno= ret;
++  }
++  else if (ret != -ENOSYS) /* -ENOSYS - no provider */
++  {
++    WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret));
++
++    /* m_mdl_blocks_commits_lock is always NULL here */
++    wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
++    my_error(ER_LOCK_DEADLOCK, MYF(0));
++    DBUG_RETURN(TRUE);
++  }
++#endif /* WITH_WSREP */
+   DBUG_RETURN(FALSE);
+ }
+diff --git a/sql/log.cc b/sql/log.cc
+index 808c176..caa23d2 100644
+--- a/sql/log.cc
++++ b/sql/log.cc
+@@ -39,6 +39,9 @@
+ #include <my_dir.h>
+ #include <stdarg.h>
+ #include <m_ctype.h>                          // For test_if_number
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif /* WITH_WSREP */
+ #ifdef _WIN32
+ #include "message.h"
+@@ -300,7 +303,6 @@ bool LOGGER::is_log_table_enabled(uint log_table_type)
+   }
+ }
+-
+ /* Check if a given table is opened log table */
+ int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
+                        const char *table_name, bool check_if_opened)
+@@ -2435,6 +2437,7 @@ int my_plugin_log_message(MYSQL_PLUGIN *plugin_ptr, plugin_log_level level,
+ /********* transaction coordinator log for 2pc - mmap() based solution *******/
++
+ /*
+   the log consists of a file, mmapped to a memory.
+   file is divided on pages of tc_log_page_size size.
+@@ -2550,8 +2553,14 @@ int TC_LOG_MMAP::open(const char *opt_name)
+     mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST);
+     mysql_cond_init(key_PAGE_cond, &pg->cond, 0);
+     pg->start=(my_xid *)(data + i*tc_log_page_size);
++#ifdef WITH_WSREP
++    if (!WSREP_ON) 
++#endif /* WITH_WSREP */
+     pg->end=(my_xid *)(pg->start + tc_log_page_size);
+     pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
++#ifdef WITH_WSREP
++    if (WSREP_ON) pg->end=pg->start + pg->size;
++#endif /* WITH_WSREP */
+   }
+   pages[0].size=pages[0].free=
+                 (tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
+diff --git a/sql/log.h b/sql/log.h
+index 6536c9e..aaefce9 100644
+--- a/sql/log.h
++++ b/sql/log.h
+@@ -104,6 +104,14 @@ class TC_LOG
+   virtual int prepare(THD *thd, bool all) = 0;
+ };
++#ifdef WITH_WSREP
++/*
++  Wrappers to MYSQL_BIN_LOG commit()/rollback() when wsrep_emulate_bin_log
++  is on.
++ */
++TC_LOG::enum_result wsrep_thd_binlog_commit(THD* thd, bool all);
++int wsrep_thd_binlog_rollback(THD * thd, bool all);
++#endif /* WITH_WSREP */
+ class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
+ {
+@@ -112,10 +120,18 @@ public:
+   int open(const char *opt_name)        { return 0; }
+   void close()                          { }
+   enum_result commit(THD *thd, bool all) {
++#ifdef WITH_WSREP
++    return wsrep_thd_binlog_commit(thd, all);
++#else
+     return ha_commit_low(thd, all) ? RESULT_ABORTED : RESULT_SUCCESS;
++#endif /* WITH_WSREP */
+   }
+   int rollback(THD *thd, bool all) {
++#ifdef WITH_WSREP
++    return wsrep_thd_binlog_rollback(thd, all);
++#else
+     return ha_rollback_low(thd, all);
++#endif /* WITH_WSREP */
+   }
+   int prepare(THD *thd, bool all) {
+     return ha_prepare_low(thd, all);
+@@ -542,12 +558,28 @@ enum enum_binlog_row_image {
+ };
+ enum enum_binlog_format {
++  /*
++    statement-based except for cases where only row-based can work (UUID()
++    etc):
++  */
+   BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected
+   BINLOG_FORMAT_STMT=  1, ///< statement-based
+   BINLOG_FORMAT_ROW=   2, ///< row-based
+   BINLOG_FORMAT_UNSPEC=3  ///< thd_binlog_format() returns it when binlog is closed
+ };
++#ifdef WITH_WSREP
++IO_CACHE* get_trans_log(THD * thd);
++bool wsrep_trans_cache_is_empty(THD *thd);
++void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end);
++void thd_binlog_trx_reset(THD * thd);
++
++#define WSREP_BINLOG_FORMAT(my_format)                         \
++   ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ?     \
++   wsrep_forced_binlog_format : my_format)
++#else
++#define WSREP_BINLOG_FORMAT(my_format) my_format
++#endif /* WITH_WSREP */
+ int query_error_code(THD *thd, bool not_killed);
+ uint purge_log_get_error_code(int res);
+diff --git a/sql/log_event.cc b/sql/log_event.cc
+index d4176cb..9173566 100644
+--- a/sql/log_event.cc
++++ b/sql/log_event.cc
+@@ -45,6 +45,9 @@
+ #include "rpl_rli_pdb.h"
+ #include "sql_show.h"    // append_identifier
+ #include <mysql/psi/mysql_statement.h>
++#if WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif
+ #define window_size Log_throttle::LOG_THROTTLE_WINDOW_SIZE
+ Error_log_throttle
+ slave_ignored_err_throttle(window_size,
+@@ -3583,6 +3586,14 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
+    master_data_written(0), mts_accessed_dbs(0)
+ {
++#ifdef WITH_WSREP
++  /*
++    If Query_log_event will contain non trans keyword (not BEGIN, COMMIT,
++    SAVEPOINT or ROLLBACK) we disable PA for this transaction.
++   */
++  if (!is_trans_keyword())
++    thd->wsrep_PA_safe= false;
++#endif /* WITH_WSREP */
+   memset(&user, 0, sizeof(user));
+   memset(&host, 0, sizeof(host));
+@@ -11160,6 +11171,18 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
+     if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0))
+     {
+       uint actual_error= thd->get_stmt_da()->sql_errno();
++#ifdef WITH_WSREP
++      if (WSREP(thd))
++      {
++        WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
++                   "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
++                   thd->get_stmt_da()->sql_errno(),
++                   thd->is_fatal_error,
++                   thd->wsrep_exec_mode,
++                   thd->wsrep_conflict_state,
++                   (long long)wsrep_thd_trx_seqno(thd));
++      } 
++#endif
+       if (thd->is_slave_error || thd->is_fatal_error)
+       {
+         /*
+@@ -12132,7 +12155,12 @@ check_table_map(Relay_log_info const *rli, RPL_TABLE_LIST *table_list)
+   DBUG_ENTER("check_table_map");
+   enum_tbl_map_status res= OK_TO_PROCESS;
++#ifdef WITH_WSREP
++  if ((rli->info_thd->slave_thread /* filtering is for slave only */  ||
++       (WSREP(rli->info_thd) && rli->info_thd->wsrep_applier))        &&
++#else
+   if (rli->info_thd->slave_thread /* filtering is for slave only */ &&
++#endif /* WITH_WSREP */
+       (!rpl_filter->db_ok(table_list->db) ||
+        (rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list))))
+     res= FILTERED_OUT;
+@@ -12865,8 +12893,23 @@ int
+ Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
+ {
+   DBUG_ASSERT(m_table != NULL);
++#ifdef WITH_WSREP
++#ifdef WSREP_PROC_INFO
++  char info[64];
++  info[sizeof(info) - 1] = '\0';
++  snprintf(info, sizeof(info) - 1, "Write_rows_log_event::write_row(%lld)",
++           (long long) wsrep_thd_trx_seqno(thd));
++  const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL;
++#else
++  const char* tmp = (WSREP(thd)) ?
++    thd_proc_info(thd,"Write_rows_log_event::write_row()") :  NULL;
++#endif /* WSREP_PROC_INFO */
++#endif /* WITH_WSREP */
+   int error= write_row(rli, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
++#ifdef WITH_WSREP
++  if (WSREP(thd)) thd_proc_info(thd, tmp);
++#endif /* WITH_WSREP */
+   if (error && !thd->is_error())
+   {
+     DBUG_ASSERT(0);
+diff --git a/sql/mdl.cc b/sql/mdl.cc
+index 70a33ab..ea79bec 100644
+--- a/sql/mdl.cc
++++ b/sql/mdl.cc
+@@ -24,6 +24,17 @@
+ #include <mysql/psi/mysql_stage.h>
+ #include <my_murmur3.h>
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#include "wsrep_thd.h"
++extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
++extern "C" char *wsrep_thd_query(THD *thd);
++void sql_print_information(const char *format, ...)
++  ATTRIBUTE_FORMAT(printf, 1, 2);
++extern bool
++wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
++                          MDL_ticket *ticket);
++#endif /* WITH_WSREP */
+ #ifdef HAVE_PSI_INTERFACE
+ static PSI_mutex_key key_MDL_map_mutex;
+ static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
+@@ -1389,11 +1400,54 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
+     called by other threads.
+   */
+   DBUG_ASSERT(ticket->get_lock());
++#ifdef WITH_WSREP
++  if ((this == &(ticket->get_lock()->m_waiting)) &&
++      wsrep_thd_is_BF((void *)(ticket->get_ctx()->wsrep_get_thd()), false))
++  {
++    Ticket_iterator itw(ticket->get_lock()->m_waiting);
++    Ticket_iterator itg(ticket->get_lock()->m_granted);
++
++    MDL_ticket *waiting, *granted;
++    MDL_ticket *prev=NULL;
++    bool added= false;
++
++    while ((waiting= itw++) && !added)
++    {
++      if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->wsrep_get_thd()), true))
++      {
++        WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", 
++                    wsrep_thd_thread_id(waiting->get_ctx()->wsrep_get_thd()), 
++                    wsrep_thd_query(waiting->get_ctx()->wsrep_get_thd()));
++        m_list.insert_after(prev, ticket);
++        added= true;
++      }
++      prev= waiting;
++    }
++    if (!added)   m_list.push_back(ticket);
++
++    while ((granted= itg++))
++    {
++      if (granted->get_ctx() != ticket->get_ctx() &&
++          granted->is_incompatible_when_granted(ticket->get_type()))
++      {
++        if (!wsrep_grant_mdl_exception(ticket->get_ctx(), granted))
++        {
++          WSREP_DEBUG("MDL victim killed at add_ticket");
++        }
++      }
++    }
++  }
++  else
++  {
++#endif /* WITH_WSREP */
+   /*
+     Add ticket to the *back* of the queue to ensure fairness
+     among requests with the same priority.
+   */
+   m_list.push_back(ticket);
++#ifdef WITH_WSREP
++  }
++#endif /* WITH_WSREP */
+   m_bitmap|= MDL_BIT(ticket->get_type());
+ }
+@@ -1709,7 +1763,6 @@ MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
+   0
+ };
+-
+ /**
+   Check if request for the metadata lock can be satisfied given its
+   current state.
+@@ -1734,6 +1787,9 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg,
+   bool can_grant= FALSE;
+   bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg];
+   bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg];
++#ifdef WITH_WSREP
++  bool  wsrep_can_grant= TRUE;
++#endif /* WITH_WSREP */
+   /*
+     New lock request can be satisfied iff:
+@@ -1756,12 +1812,59 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg,
+       {
+         if (ticket->get_ctx() != requestor_ctx &&
+             ticket->is_incompatible_when_granted(type_arg))
++#ifdef WITH_WSREP
++        {
++          if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()),false) &&
++              key.mdl_namespace() == MDL_key::GLOBAL)
++          {
++            WSREP_DEBUG("global lock granted for BF: %lu %s",
++                        wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), 
++                        wsrep_thd_query(requestor_ctx->wsrep_get_thd()));
++            can_grant = true;
++          }
++          else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket))
++          {
++            wsrep_can_grant= FALSE;
++          if (wsrep_log_conflicts) 
++          {
++            MDL_lock * lock = ticket->get_lock();
++            WSREP_INFO(
++                "MDL conflict db=%s table=%s ticket=%d solved by %s",
++                lock->key.db_name(), lock->key.name(), ticket->get_type(), "abort"
++                    );
++            }
++          }
++          else
++          {     
++            can_grant= TRUE;
++          }
++        }
++#else
+           break;
++#endif /* WITH_WSREP */
+       }
++#ifdef WITH_WSREP
++      if ((ticket == NULL) && wsrep_can_grant)
++#else
+       if (ticket == NULL)             /* Incompatible locks are our own. */
++#endif /* WITH_WSREP */
++
+         can_grant= TRUE;
+     }
+   }
++#ifdef WITH_WSREP
++  else
++  {
++    if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()), false) &&
++      key.mdl_namespace() == MDL_key::GLOBAL)
++    {
++      WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s",
++                wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), 
++                wsrep_thd_query(requestor_ctx->wsrep_get_thd()));
++      can_grant = true;
++    }
++  }
++#endif /* WITH_WSREP */
+   return can_grant;
+ }
+@@ -2780,6 +2883,12 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
+ }
++#ifdef WITH_WSREP
++void MDL_context::release_explicit_locks()
++{
++  release_locks_stored_before(MDL_EXPLICIT, NULL);
++}
++#endif
+ /**
+   Release all explicit locks in the context which correspond to the
+   same name/object as this lock request.
+@@ -3068,3 +3177,32 @@ void MDL_context::set_transaction_duration_for_all_locks()
+     ticket->m_duration= MDL_TRANSACTION;
+ #endif
+ }
++#ifdef WITH_WSREP
++void MDL_ticket::wsrep_report(bool debug)
++{
++  if (debug) 
++    {
++      WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s",
++               (get_type()  == MDL_INTENTION_EXCLUSIVE)  ? "intention exclusive"  :
++               ((get_type() == MDL_SHARED)               ? "shared"               :
++               ((get_type() == MDL_SHARED_HIGH_PRIO      ? "shared high prio"     :
++               ((get_type() == MDL_SHARED_READ)          ? "shared read"          :
++               ((get_type() == MDL_SHARED_WRITE)         ? "shared write"         :
++               ((get_type() == MDL_SHARED_NO_WRITE)      ? "shared no write"      :
++         ((get_type() == MDL_SHARED_NO_READ_WRITE) ? "shared no read write" :
++               ((get_type() == MDL_EXCLUSIVE)            ? "exclusive"            :
++          "UNKNOWN")))))))),
++         (m_lock->key.mdl_namespace()  == MDL_key::GLOBAL) ? "GLOBAL"       :
++         ((m_lock->key.mdl_namespace() == MDL_key::SCHEMA) ? "SCHEMA"       :
++         ((m_lock->key.mdl_namespace() == MDL_key::TABLE)  ? "TABLE"        :
++         ((m_lock->key.mdl_namespace() == MDL_key::TABLE)  ? "FUNCTION"     :
++         ((m_lock->key.mdl_namespace() == MDL_key::TABLE)  ? "PROCEDURE"    :
++         ((m_lock->key.mdl_namespace() == MDL_key::TABLE)  ? "TRIGGER"      :
++         ((m_lock->key.mdl_namespace() == MDL_key::TABLE)  ? "EVENT"        :
++         ((m_lock->key.mdl_namespace() == MDL_key::COMMIT) ? "COMMIT"       :
++         (char *)"UNKNOWN"))))))),
++         m_lock->key.db_name(),
++         m_lock->key.name());
++    }
++}
++#endif /* WITH_WSREP */
+diff --git a/sql/mdl.h b/sql/mdl.h
+index ddbd55a..2d2502e 100644
+--- a/sql/mdl.h
++++ b/sql/mdl.h
+@@ -577,6 +577,9 @@ public:
+   MDL_ticket *next_in_lock;
+   MDL_ticket **prev_in_lock;
+ public:
++#ifdef WITH_WSREP
++  void wsrep_report(bool debug);
++#endif /* WITH_WSREP */
+   bool has_pending_conflicting_lock() const;
+   MDL_context *get_ctx() const { return m_ctx; }
+@@ -763,6 +766,13 @@ public:
+              m_tickets[MDL_EXPLICIT].is_empty());
+   }
++#ifdef WITH_WSREP
++  inline bool has_transactional_locks() const
++  {
++    return !m_tickets[MDL_TRANSACTION].is_empty();
++  }
++#endif /* WITH_WSREP */
++
+   MDL_savepoint mdl_savepoint()
+   {
+     return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
+@@ -775,6 +785,9 @@ public:
+   void release_statement_locks();
+   void release_transactional_locks();
++#ifdef WITH_WSREP
++  void release_explicit_locks();
++#endif
+   void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
+   MDL_context_owner *get_owner() { return m_owner; }
+@@ -908,6 +921,9 @@ private:
+                              MDL_ticket **out_ticket);
+ public:
++#ifdef WITH_WSREP
++  THD *wsrep_get_thd() const { return get_thd(); }
++#endif /* WITH_WSREP */
+   void find_deadlock();
+   bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor);
+diff --git a/sql/mysqld.cc b/sql/mysqld.cc
+index fa68613..8ed210f 100644
+--- a/sql/mysqld.cc
++++ b/sql/mysqld.cc
+@@ -72,6 +72,12 @@
+ #include "probes_mysql.h"
+ #include "scheduler.h"
+ #include "debug_sync.h"
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#include "wsrep_var.h"
++#include "wsrep_thd.h"
++#include "wsrep_sst.h"
++#endif
+ #include "sql_callback.h"
+ #include "opt_trace_context.h"
+@@ -483,6 +489,10 @@ ulong binlog_checksum_options;
+ my_bool opt_master_verify_checksum= 0;
+ my_bool opt_slave_sql_verify_checksum= 1;
+ const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
++#ifdef WITH_WSREP
++const char *wsrep_binlog_format_names[]= 
++                                   {"MIXED", "STATEMENT", "ROW", "NONE", NullS};
++#endif /*WITH_WSREP */
+ my_bool enforce_gtid_consistency;
+ my_bool binlog_gtid_simple_recovery;
+ ulong binlog_error_action;
+@@ -747,6 +757,23 @@ pthread_attr_t connection_attrib;
+ mysql_mutex_t LOCK_server_started;
+ mysql_cond_t COND_server_started;
++#ifdef WITH_WSREP
++mysql_mutex_t LOCK_wsrep_ready;
++mysql_cond_t  COND_wsrep_ready;
++mysql_mutex_t LOCK_wsrep_sst;
++mysql_cond_t  COND_wsrep_sst;
++mysql_mutex_t LOCK_wsrep_sst_init;
++mysql_cond_t  COND_wsrep_sst_init;
++mysql_mutex_t LOCK_wsrep_rollback;
++mysql_cond_t  COND_wsrep_rollback;
++wsrep_aborting_thd_t wsrep_aborting_thd= NULL;
++mysql_mutex_t LOCK_wsrep_replaying;
++mysql_cond_t  COND_wsrep_replaying;
++mysql_mutex_t LOCK_wsrep_slave_threads;
++mysql_mutex_t LOCK_wsrep_desync;
++int wsrep_replaying= 0;
++static void wsrep_close_threads(THD* thd);
++#endif /* WITH_WSREP */
+ int mysqld_server_started= 0;
+ File_parser_dummy_hook file_parser_dummy_hook;
+@@ -1209,7 +1236,9 @@ bool mysqld_embedded=0;
+ bool mysqld_embedded=1;
+ #endif
++#ifndef EMBEDDED_LIBRARY
+ static my_bool plugins_are_initialized= FALSE;
++#endif
+ #ifndef DBUG_OFF
+ static const char* default_dbug_option;
+@@ -1421,6 +1450,11 @@ static void close_connections(void)
+     /* We skip slave threads & scheduler on this first loop through. */
+     if (tmp->slave_thread)
+       continue;
++#ifdef WITH_WSREP
++    /* skip wsrep system threads as well */
++    if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier))
++      continue;
++#endif /* WITH_WSREP */
+     if (tmp->get_command() == COM_BINLOG_DUMP ||
+         tmp->get_command() == COM_BINLOG_DUMP_GTID)
+     {
+@@ -1523,6 +1557,33 @@ static void close_connections(void)
+                            tmp->main_security_ctx.user : ""));
+       close_connection(tmp);
+     }
++#ifdef WITH_WSREP
++    /*
++     * TODO: this code block may turn out redundant. wsrep->disconnect()
++     *       should terminate slave threads gracefully, and we don't need
++     *       to signal them here. 
++     *       The code here makes sure mysqld will not hang during shutdown
++     *       even if wsrep provider has problems in shutting down.
++     */
++    if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV)
++    {
++      sql_print_information("closing wsrep system thread");
++      tmp->killed= THD::KILL_CONNECTION;
++      MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
++      if (tmp->mysys_var)
++      {
++      tmp->mysys_var->abort=1;
++      mysql_mutex_lock(&tmp->mysys_var->mutex);
++      if (tmp->mysys_var->current_cond)
++        {
++        mysql_mutex_lock(tmp->mysys_var->current_mutex);
++        mysql_cond_broadcast(tmp->mysys_var->current_cond);
++        mysql_mutex_unlock(tmp->mysys_var->current_mutex);
++      }
++      mysql_mutex_unlock(&tmp->mysys_var->mutex);
++      }
++    }
++#endif
+   }
+   DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
+   mysql_mutex_unlock(&LOCK_thread_count);
+@@ -1672,8 +1733,14 @@ static void __cdecl kill_server(int sig_ptr)
+     }
+   }
+ #endif
++#ifdef WITH_WSREP
++  if (WSREP_ON) wsrep_stop_replication(NULL);
++#endif
+   close_connections();
++#ifdef WITH_WSREP
++  if (WSREP_ON) wsrep_deinit();
++#endif
+   if (sig != MYSQL_KILL_SIGNAL &&
+       sig != 0)
+     unireg_abort(1);        /* purecov: inspected */
+@@ -1768,6 +1835,23 @@ extern "C" void unireg_abort(int exit_code)
+     usage();
+   if (exit_code)
+     sql_print_error("Aborting\n");
++
++#ifdef WITH_WSREP
++  if (wsrep)
++  {
++    /* This is an abort situation, we cannot expect to gracefully close all
++     * wsrep threads here, we can only diconnect from service */
++    wsrep_close_client_connections(FALSE);
++    shutdown_in_progress= 1;
++    THD* thd(0);
++    wsrep->disconnect(wsrep);
++    WSREP_INFO("Service disconnected.");
++    wsrep_close_threads(thd); /* this won't close all threads */
++    sleep(1); /* so give some time to exit for those which can */
++    WSREP_INFO("Some threads may fail to exit.");
++  }
++#endif // WITH_WSREP
++
+   clean_up(!opt_help && (exit_code || !opt_bootstrap)); /* purecov: inspected */
+   DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
+   mysqld_exit(exit_code);
+@@ -2015,6 +2099,20 @@ static void clean_up_mutexes()
+   mysql_cond_destroy(&COND_thread_cache);
+   mysql_cond_destroy(&COND_flush_thread_cache);
+   mysql_cond_destroy(&COND_manager);
++#ifdef WITH_WSREP
++  (void) mysql_mutex_destroy(&LOCK_wsrep_ready);
++  (void) mysql_cond_destroy(&COND_wsrep_ready);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_sst);
++  (void) mysql_cond_destroy(&COND_wsrep_sst);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_sst_init);
++  (void) mysql_cond_destroy(&COND_wsrep_sst_init);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_rollback);
++  (void) mysql_cond_destroy(&COND_wsrep_rollback);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_replaying);
++  (void) mysql_cond_destroy(&COND_wsrep_replaying);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_slave_threads);
++  (void) mysql_mutex_destroy(&LOCK_wsrep_desync);
++#endif
+ }
+ #endif /*EMBEDDED_LIBRARY*/
+@@ -2463,6 +2561,9 @@ static void network_init(void)
+           socket_errno);
+       unireg_abort(1);
+     }
++#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
++    (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC);
++#endif /* WITH_WSREP */
+   }
+ #ifdef _WIN32
+@@ -2559,6 +2660,9 @@ static void network_init(void)
+     if (mysql_socket_listen(unix_sock, (int)back_log) < 0)
+       sql_print_warning("listen() on Unix socket failed with error %d",
+           socket_errno);
++#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
++    (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC);
++#endif /* WITH_WSREP */
+   }
+ #endif
+   DBUG_PRINT("info",("server started"));
+@@ -2578,7 +2682,11 @@ static void network_init(void)
+   @note
+     For the connection that is doing shutdown, this is called twice
+ */
++#ifdef WITH_WSREP
++void close_connection(THD *thd, uint sql_errno, bool lock)
++#else
+ void close_connection(THD *thd, uint sql_errno)
++#endif
+ {
+   DBUG_ENTER("close_connection");
+@@ -2752,6 +2860,13 @@ bool one_thread_per_connection_end(THD *thd, bool block_pthread)
+     block_pthread= false;
+   }
++#ifdef WITH_WSREP
++  if (WSREP(thd) && thd->wsrep_applier)
++  {
++    WSREP_DEBUG("avoiding thread re-use for applier, thd: %lu", thd->thread_id);
++    block_pthread= false;
++  }
++#endif /* WITH_WSREP */
+   // Clean up errors now, before possibly waiting for a new connection.
+ #ifndef EMBEDDED_LIBRARY
+   ERR_remove_state(0);
+@@ -3792,6 +3907,13 @@ int init_common_variables()
+     strmake(default_logfile_name, glob_hostname,
+       sizeof(default_logfile_name)-5);
++#ifdef WITH_WSREP
++  if (0 == wsrep_node_name || 0 == wsrep_node_name[0])
++  {
++    my_free((void *)wsrep_node_name);
++    wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME));
++  }
++#endif /* WITH_WSREP */
+   strmake(pidfile_name, default_logfile_name, sizeof(pidfile_name)-5);
+   strmov(fn_ext(pidfile_name),".pid");    // Add proper extension
+@@ -3851,7 +3973,11 @@ int init_common_variables()
+   compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 ==
+                      SQLCOM_END + 8);
+ #endif
+-
++#ifdef WITH_WSREP
++  /* This is a protection against mutually incompatible option values. */
++  if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv))
++    return 1;
++#endif /* WITH_WSREP */
+   if (get_options(&remaining_argc, &remaining_argv))
+     return 1;
+   set_server_version();
+@@ -4260,6 +4386,27 @@ static int init_thread_environment()
+     sql_print_error("Can't create thread-keys");
+     return 1;
+   }
++#ifdef WITH_WSREP
++  mysql_mutex_init(key_LOCK_wsrep_ready,
++                   &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL);
++  mysql_mutex_init(key_LOCK_wsrep_sst,
++                   &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL);
++  mysql_mutex_init(key_LOCK_wsrep_sst_init,
++                   &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL);
++  mysql_mutex_init(key_LOCK_wsrep_rollback,
++                   &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL);
++  mysql_mutex_init(key_LOCK_wsrep_replaying,
++                   &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
++  mysql_mutex_init(key_LOCK_wsrep_slave_threads,
++                   &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
++  mysql_mutex_init(key_LOCK_wsrep_desync,
++                   &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
++#endif
+   return 0;
+ }
+@@ -4602,7 +4749,6 @@ initialize_storage_engine(char *se_name, const char *se_kind,
+   return false;
+ }
+-
+ static int init_server_components()
+ {
+   DBUG_ENTER("init_server_components");
+@@ -4700,7 +4846,11 @@ static int init_server_components()
+     sql_print_warning("You need to use --log-bin to make "
+                     "--log-slave-updates work.");
+   }
++#ifdef WITH_WSREP
++  if (!WSREP_ON && binlog_format_used && !opt_bin_log)
++#else
+   if (binlog_format_used && !opt_bin_log)
++#endif
+     sql_print_warning("You need to use --log-bin to make "
+                       "--binlog-format work.");
+@@ -4783,10 +4933,67 @@ a file name for --log-bin-index option", opt_binlog_index_name);
+       my_free(opt_bin_logname);
+       opt_bin_logname=my_strdup(buf, MYF(0));
+     }
++#ifdef WITH_WSREP /* WSREP BEFORE SE */
++    /*
++      Wsrep initialization must happen at this point, because:
++      - opt_bin_logname must be known when starting replication
++        since SST may need it
++      - SST may modify binlog index file, so it must be opened
++        after SST has happened
++     */
++  }
++  if (!wsrep_recovery)
++  {
++    if (opt_bootstrap) // bootsrap option given - disable wsrep functionality
++    {
++      wsrep_provider_init(WSREP_NONE);
++      if (wsrep_init()) unireg_abort(1);
++    }
++    else // full wsrep initialization
++    {
++      // add basedir/bin to PATH to resolve wsrep script names
++      char* const tmp_path((char*)alloca(strlen(mysql_home) +
++                                           strlen("/bin") + 1));
++      if (tmp_path)
++      {
++        strcpy(tmp_path, mysql_home);
++        strcat(tmp_path, "/bin");
++        wsrep_prepend_PATH(tmp_path);
++      }
++      else
++      {
++        WSREP_ERROR("Could not append %s/bin to PATH", mysql_home);
++      }
++
++      if (wsrep_before_SE())
++      {
++        set_ports(); // this is also called in network_init() later but we need
++                     // to know mysqld_port now - lp:1071882
++        wsrep_init_startup(true);
++      }
++    }
++  }
++  if (opt_bin_log)
++  {
++    /*
++      Variable ln is not defined at this scope. We use opt_bin_logname instead.
++      It should be the same as ln since
++      - mysql_bin_log.generate_name() returns first argument if new log name
++        is not generated
++      - if new log name is generated, return value is assigned to ln and copied
++        to opt_bin_logname above
++     */
++    if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname,
++                                      TRUE))
++    {
++      unireg_abort(1);
++    }
++#else
+     if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE))
+     {
+       unireg_abort(1);
+     }
++#endif /* WITH_WSREP */
+   }
+   if (opt_bin_log)
+@@ -4844,6 +5051,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
+     unireg_abort(1);
+   }
++#ifdef WITH_WSREP
+   if (plugin_init(&remaining_argc, remaining_argv,
+                   (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
+                   (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
+@@ -4852,7 +5060,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
+     unireg_abort(1);
+   }
+   plugins_are_initialized= TRUE;  /* Don't separate from init function */
+-
++#endif /* WITH_WSREP */
+   /* we do want to exit if there are any other unknown options */
+   if (remaining_argc > 1)
+   {
+@@ -4947,16 +5155,34 @@ a file name for --log-bin-index option", opt_binlog_index_name);
+                                 &global_system_variables.temp_table_plugin))
+     unireg_abort(1);
++#ifdef WITH_WSREP
++  if (!opt_bin_log)
++  {
++    wsrep_emulate_bin_log= 1;
++  }
++#endif
+   if (total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log))
+   {
+     if (opt_bin_log)
+       tc_log= &mysql_bin_log;
+     else
++#ifdef WITH_WSREP
++      if (WSREP_ON)
++        tc_log=  &tc_log_dummy;
++      else
++#endif /* WITH_WSREP */
+       tc_log= &tc_log_mmap;
+   }
+   else
+     tc_log= &tc_log_dummy;
++#ifdef WITH_WSREP
++  WSREP_DEBUG("Initial TC log open: %s", 
++              (tc_log == &mysql_bin_log) ? "binlog" :
++              (tc_log == &tc_log_mmap) ? "mmap" :
++              (tc_log == &tc_log_dummy) ? "dummy" : "unknown"
++              );
++#endif
+   if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
+   {
+     sql_print_error("Can't init tc log");
+@@ -5047,8 +5273,6 @@ a file name for --log-bin-index option", opt_binlog_index_name);
+   init_update_queries();
+   DBUG_RETURN(0);
+ }
+-
+-
+ #ifndef EMBEDDED_LIBRARY
+ static void create_shutdown_thread()
+@@ -5070,6 +5294,421 @@ static void create_shutdown_thread()
+ #endif /* EMBEDDED_LIBRARY */
++#ifdef WITH_WSREP
++typedef void (*wsrep_thd_processor_fun)(THD *);
++
++pthread_handler_t start_wsrep_THD(void *arg)
++{
++  THD *thd;
++  wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg;
++
++  if (my_thread_init())
++  {
++    WSREP_ERROR("Could not initialize thread");
++    return(NULL);
++  }
++
++  if (!(thd= new THD(true, true)))
++  {
++    return(NULL);
++  }
++  mysql_mutex_lock(&LOCK_thread_count);
++  thd->thread_id=thread_id++;
++
++  thd->real_id=pthread_self(); // Keep purify happy
++  add_global_thread(thd);
++  thread_created++;
++
++  my_net_init(&thd->net,(st_vio*) 0);
++
++  DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id));
++  thd->prior_thr_create_utime= thd->start_utime= my_micro_time();
++  (void) mysql_mutex_unlock(&LOCK_thread_count);
++
++  /* from bootstrap()... */
++  thd->bootstrap=1;
++  thd->max_client_packet_length= thd->net.max_packet;
++  thd->security_ctx->master_access= ~(ulong)0;
++
++  /* from handle_one_connection... */
++  pthread_detach_this_thread();
++
++  mysql_thread_set_psi_id(thd->thread_id);
++  thd->thr_create_utime= my_micro_time();
++  if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
++  {
++    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++    statistic_increment(aborted_connects,&LOCK_status);
++    MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
++
++    return(NULL);
++  }
++
++  /* now that we've called my_thread_init(), it is safe to call DBUG_* */
++
++  thd->thread_stack= (char*) &thd;
++  if (thd->store_globals())
++  {
++    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++    statistic_increment(aborted_connects,&LOCK_status);
++    MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
++    delete thd;
++
++    return(NULL);
++  }
++
++  /* from handle_bootstrap() */
++
++  thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
++  thd->security_ctx->skip_grants();
++
++  /* handle_one_connection() again... */
++  //thd->version= refresh_version;
++  thd->proc_info= 0;
++  thd->set_command(COM_SLEEP);
++  thd->set_time();
++  thd->init_for_queries();
++
++  mysql_mutex_lock(&LOCK_connection_count);
++  ++connection_count;
++  mysql_mutex_unlock(&LOCK_connection_count);
++
++  processor(thd);
++
++  close_connection(thd, 0, 1);
++
++  // Note: We can't call THD destructor without crashing
++  // if plugins have not been initialized. However, in most of the
++  // cases this means that pre SE initialization SST failed and
++  // we are going to exit anyway.
++  if (plugins_are_initialized)
++  {
++    net_end(&thd->net);
++    MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1));
++  }
++  else
++  {
++    // TODO: lightweight cleanup to get rid of:
++    // 'Error in my_thread_global_end(): 2 threads didn't exit'
++    // at server shutdown
++  }
++  return(NULL);
++}
++
++/**/
++static bool abort_replicated(THD *thd)
++{
++  bool ret_code= false;
++  if (thd->wsrep_query_state== QUERY_COMMITTING)
++  {
++    if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id);
++
++    (void)wsrep_abort_thd(thd, thd, TRUE);
++    ret_code= true;
++  }
++  return ret_code;
++}
++/**/
++static inline bool is_client_connection(THD *thd)
++{
++#if REMOVE
++// REMOVE THIS LATER (lp:777201). Below we had to add an explicit check for
++// wsrep_applier since wsrep_exec_mode didn't seem to always work
++if (thd->wsrep_applier && thd->wsrep_exec_mode != REPL_RECV)
++WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode);
++
++  if ( thd->slave_thread               || /* declared as mysql slave  */
++       thd->system_thread              || /* declared as system thread */
++      !thd->vio_ok()                   || /* server internal thread */
++       thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */
++       thd->wsrep_applier              || /* wsrep slave applier */
++      !thd->variables.wsrep_on)           /* client, but fenced outside wsrep */
++    return false;
++
++  return true;
++#else
++  return (thd->wsrep_client_thread && thd->variables.wsrep_on);
++#endif /* REMOVE */
++}
++
++static inline bool is_replaying_connection(THD *thd)
++{
++  bool ret;
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  ret=  (thd->wsrep_conflict_state == REPLAYING) ? true : false;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  return ret;
++}
++
++static inline bool is_committing_connection(THD *thd)
++{
++  bool ret;
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  ret=  (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  return ret;
++}
++
++static bool have_client_connections()
++{
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++    DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
++                        tmp->thread_id));
++    if (is_client_connection(tmp) && tmp->killed == THD::KILL_CONNECTION)
++    {
++      (void)abort_replicated(tmp);
++      return true;
++    }
++  }
++  return false;
++}
++
++/*
++   returns the number of wsrep appliers running.
++   However, the caller (thd parameter) is not taken in account
++ */
++static int have_wsrep_appliers(THD *thd)
++{
++  int ret= 0;
++
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++    ret+= (tmp != thd && tmp->wsrep_applier);
++  }
++  return ret;
++}
++
++static void wsrep_close_thread(THD *thd)
++{
++  thd->killed= THD::KILL_CONNECTION;
++  MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
++  if (thd->mysys_var)
++  {
++    thd->mysys_var->abort=1;
++    mysql_mutex_lock(&thd->mysys_var->mutex);
++    if (thd->mysys_var->current_cond)
++    {
++      mysql_mutex_lock(thd->mysys_var->current_mutex);
++      mysql_cond_broadcast(thd->mysys_var->current_cond);
++      mysql_mutex_unlock(thd->mysys_var->current_mutex);
++    }
++    mysql_mutex_unlock(&thd->mysys_var->mutex);
++  }
++}
++
++static my_bool have_committing_connections()
++{
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++
++    if (!is_client_connection(tmp))
++      continue;
++
++    if (is_committing_connection(tmp))
++    {
++      return TRUE;
++    }
++  }
++  return FALSE;
++}
++
++int wsrep_wait_committing_connections_close(int wait_time)
++{
++  int sleep_time= 100;
++
++  while (have_committing_connections() && wait_time > 0)
++  {
++    WSREP_DEBUG("wait for committing transaction to close: %d", wait_time);
++    my_sleep(sleep_time);
++    wait_time -= sleep_time;
++  }
++  if (have_committing_connections())
++  {
++    return 1;
++  }
++  return 0;
++}
++
++void wsrep_close_client_connections(my_bool wait_to_end) 
++{
++  /*
++    First signal all threads that it's time to die
++  */
++
++  /* Kill blocked pthreads */
++  kill_blocked_pthreads_flag++;
++  kill_blocked_pthreads();
++
++  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
++
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++    DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
++                        tmp->thread_id));
++    /* We skip slave threads & scheduler on this first loop through. */
++    if (!is_client_connection(tmp))
++      continue;
++
++    if (is_replaying_connection(tmp))
++    {
++      tmp->killed= THD::KILL_CONNECTION;
++      continue;
++    }
++
++    /* replicated transactions must be skipped */
++    if (abort_replicated(tmp))
++      continue;
++
++    WSREP_DEBUG("closing connection %ld", tmp->thread_id);
++    wsrep_close_thread(tmp);
++  }
++  mysql_mutex_unlock(&LOCK_thread_count);
++
++  if (get_thread_count() > 0)
++    sleep(2);                               // Give threads time to die
++
++  mysql_mutex_lock(&LOCK_thread_count);
++  /*
++    Force remaining threads to die by closing the connection to the client
++  */
++
++  for (it= global_thread_list->begin(); it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++#ifndef __bsdi__                              // Bug in BSDI kernel
++    if (is_client_connection(tmp) && 
++        !abort_replicated(tmp)    &&
++      !is_replaying_connection(tmp))
++    {
++      WSREP_INFO("killing local connection: %ld",tmp->thread_id);
++      close_connection(tmp,0,0);
++    }
++#endif
++  }
++
++  DBUG_PRINT("quit",("Waiting for threads to die (count=%u)", get_thread_count()));
++  if (wsrep_debug)
++    WSREP_INFO("waiting for client connections to close: %u", 
++               get_thread_count());
++
++  while (wait_to_end && have_client_connections())
++  {
++    mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
++    DBUG_PRINT("quit",("One thread died (count=%u)", get_thread_count()));
++  }
++
++  mysql_mutex_unlock(&LOCK_thread_count);
++
++  /* All client connection threads have now been aborted */
++}
++
++void wsrep_close_applier(THD *thd)
++{
++  WSREP_DEBUG("closing applier %ld", thd->thread_id);
++  wsrep_close_thread(thd);
++}
++
++static void wsrep_close_threads(THD *thd)
++{
++  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
++
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++    DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
++                       tmp->thread_id));
++    /* We skip slave threads & scheduler on this first loop through. */
++    if (tmp->wsrep_applier && tmp != thd)
++    {
++      WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id);
++      wsrep_close_thread (tmp);
++    }
++  }
++
++  mysql_mutex_unlock(&LOCK_thread_count);
++}
++
++void wsrep_close_applier_threads(int count)
++{
++  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
++
++  Thread_iterator it= global_thread_list->begin();
++  for (; it != global_thread_list->end(); ++it)
++  {
++    THD *tmp= *it;
++    DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
++                       tmp->thread_id));
++    /* We skip slave threads & scheduler on this first loop through. */
++    if (tmp->wsrep_applier)
++    {
++      WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id);
++      tmp->wsrep_applier_closing= TRUE;
++      count--;
++    }
++  }
++
++  mysql_mutex_unlock(&LOCK_thread_count);
++}
++
++void wsrep_wait_appliers_close(THD *thd)
++{
++  /* Wait for wsrep appliers to gracefully exit */
++  mysql_mutex_lock(&LOCK_thread_count);
++  while (have_wsrep_appliers(thd) > 1)
++  // 1 is for rollbacker thread which needs to be killed explicitly.
++  // This gotta be fixed in a more elegant manner if we gonna have arbitrary
++  // number of non-applier wsrep threads.
++  {
++    mysql_cond_wait(&COND_thread_count,&LOCK_thread_count);
++    DBUG_PRINT("quit",("One applier died (count=%u)", get_thread_count()));
++  }
++  mysql_mutex_unlock(&LOCK_thread_count);
++  /* Now kill remaining wsrep threads: rollbacker */
++  wsrep_close_threads (thd);
++  /* and wait for them to die */
++  mysql_mutex_lock(&LOCK_thread_count);
++  while (have_wsrep_appliers(thd) > 0)
++  {
++    mysql_cond_wait(&COND_thread_count,&LOCK_thread_count);
++    DBUG_PRINT("quit",("One thread died (count=%u)", get_thread_count()));
++  }
++  mysql_mutex_unlock(&LOCK_thread_count);
++
++  /* All wsrep applier threads have now been aborted. However, if this thread
++     is also applier, we are still running...
++  */
++}
++
++void wsrep_kill_mysql(THD *thd)
++{
++  if (mysqld_server_started)
++  {
++    if (!shutdown_in_progress)
++    {
++      WSREP_INFO("starting shutdown");
++      kill_mysql();
++    }
++  }
++  else
++  {
++    unireg_abort(1);
++  }
++}
++#endif /* WITH_WSREP */
+ #if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+ static void handle_connections_methods()
+@@ -5204,6 +5843,9 @@ int mysqld_main(int argc, char **argv)
+     return 1;
+   }
+ #endif
++#ifdef WITH_WSREP
++  wsrep_filter_new_cluster (&argc, argv);
++#endif /* WITH_WSREP */
+   orig_argc= argc;
+   orig_argv= argv;
+@@ -5537,6 +6179,14 @@ int mysqld_main(int argc, char **argv)
+   my_str_free= &my_str_free_mysqld;
+   my_str_realloc= &my_str_realloc_mysqld;
++#ifdef WITH_WSREP /* WSREP AFTER SE */
++  if (wsrep_recovery)
++  {
++    select_thread_in_use= 0;
++    wsrep_recover();
++    unireg_abort(0);
++  }
++#endif /* WITH_WSREP */
+   /*
+     init signals & alarm
+     After this we can't quit by a simple unireg_abort
+@@ -5615,6 +6265,31 @@ int mysqld_main(int argc, char **argv)
+   if (Events::init(opt_noacl || opt_bootstrap))
+     unireg_abort(1);
++#ifdef WITH_WSREP /* WSREP AFTER SE */
++  if (opt_bootstrap)
++  {
++    /*! bootstrap wsrep init was taken care of above */
++  }
++  else
++  {
++    wsrep_SE_initialized();
++
++    if (wsrep_before_SE())
++    {
++      /*! in case of no SST wsrep waits in view handler callback */
++      wsrep_SE_init_grab();
++      wsrep_SE_init_done();
++      /*! in case of SST wsrep waits for wsrep->sst_received */
++      wsrep_sst_continue();
++    }
++    else
++    {
++      wsrep_init_startup (false);
++    }
++
++    wsrep_create_appliers(wsrep_slave_threads - 1);
++  }
++#endif /* WITH_WSREP */
+   if (opt_bootstrap)
+   {
+     select_thread_in_use= 0;                    // Allow 'kill' to work
+@@ -5676,6 +6351,9 @@ int mysqld_main(int argc, char **argv)
+ #ifdef EXTRA_DEBUG2
+   sql_print_error("Before Lock_thread_count");
+ #endif
++#ifdef WITH_WSREP
++  WSREP_DEBUG("Before Lock_thread_count");
++#endif
+   mysql_mutex_lock(&LOCK_thread_count);
+   DBUG_PRINT("quit", ("Got thread_count mutex"));
+   select_thread_in_use=0;     // For close_connections
+@@ -5941,6 +6619,9 @@ static void bootstrap(MYSQL_FILE *file)
+   DBUG_ENTER("bootstrap");
+   THD *thd= new THD;
++#ifdef WITH_WSREP
++  thd->variables.wsrep_on= 0;
++#endif
+   thd->bootstrap=1;
+   my_net_init(&thd->net,(st_vio*) 0);
+   thd->max_client_packet_length= thd->net.max_packet;
+@@ -6080,7 +6761,11 @@ void create_thread_to_handle_connection(THD *thd)
+       my_snprintf(error_message_buff, sizeof(error_message_buff),
+                   ER_THD(thd, ER_CANT_CREATE_THREAD), error);
+       net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL);
++#ifdef WITH_WSREP
++      close_connection(thd,0,0);
++#else
+       close_connection(thd);
++#endif
+       delete thd;
+       return;
+       /* purecov: end */
+@@ -6132,7 +6817,11 @@ static void create_new_thread(THD *thd)
+       with no sqlstate.
+       A client expecting a SQLSTATE will not find any, and assume 'HY000'.
+     */
++#ifdef WITH_WSREP
++    close_connection(thd, ER_CON_COUNT_ERROR, 1);
++#else
+     close_connection(thd, ER_CON_COUNT_ERROR);
++#endif
+     delete thd;
+     statistic_increment(connection_errors_max_connection, &LOCK_status);
+     DBUG_VOID_RETURN;
+@@ -6352,6 +7041,9 @@ void handle_connections_sockets()
+         sleep(1);       // Give other threads some time
+       continue;
+     }
++#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
++    (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
++#endif /* WITH_WSREP */
+ #ifdef HAVE_LIBWRAP
+     {
+@@ -6531,7 +7223,11 @@ pthread_handler_t handle_connections_namedpipes(void *arg)
+     if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) ||
+   my_net_init(&thd->net, thd->net.vio))
+     {
++#ifdef WITH_WSREP
++      close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#else
+       close_connection(thd, ER_OUT_OF_RESOURCES);
++#endif
+       delete thd;
+       continue;
+     }
+@@ -6726,7 +7422,11 @@ pthread_handler_t handle_connections_shared_memory(void *arg)
+                                                    event_conn_closed)) ||
+                         my_net_init(&thd->net, thd->net.vio))
+     {
++#ifdef WITH_WSREP
++      close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#else
+       close_connection(thd, ER_OUT_OF_RESOURCES);
++#endif
+       errmsg= 0;
+       goto errorconn;
+     }
+@@ -8029,6 +8729,20 @@ SHOW_VAR status_vars[]= {
+ #ifdef ENABLED_PROFILING
+   {"Uptime_since_flush_status",(char*) &show_flushstatustime,   SHOW_FUNC},
+ #endif
++#ifdef WITH_WSREP
++  {"wsrep_connected",          (char*) &wsrep_connected,         SHOW_BOOL},
++  {"wsrep_ready",              (char*) &wsrep_ready,             SHOW_BOOL},
++  {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR},
++  {"wsrep_cluster_conf_id",    (char*) &wsrep_cluster_conf_id,   SHOW_LONGLONG},
++  {"wsrep_cluster_status",     (char*) &wsrep_cluster_status,    SHOW_CHAR_PTR},
++  {"wsrep_cluster_size",       (char*) &wsrep_cluster_size,      SHOW_LONG_NOFLUSH},
++  {"wsrep_local_index",        (char*) &wsrep_local_index,       SHOW_LONG_NOFLUSH},
++  {"wsrep_local_bf_aborts",    (char*) &wsrep_show_bf_aborts,    SHOW_FUNC},
++  {"wsrep_provider_name",      (char*) &wsrep_provider_name,     SHOW_CHAR_PTR},
++  {"wsrep_provider_version",   (char*) &wsrep_provider_version,  SHOW_CHAR_PTR},
++  {"wsrep_provider_vendor",    (char*) &wsrep_provider_vendor,   SHOW_CHAR_PTR},
++  {"wsrep",                    (char*) &wsrep_show_status,       SHOW_FUNC},
++#endif
+   {NullS, NullS, SHOW_LONG}
+ };
+@@ -8356,6 +9070,10 @@ static int mysql_init_variables(void)
+     tmpenv = DEFAULT_MYSQL_HOME;
+   (void) strmake(mysql_home, tmpenv, sizeof(mysql_home)-1);
+ #endif
++#ifdef WITH_WSREP
++  if (WSREP_ON && wsrep_init_vars())
++    return 1;
++#endif
+   return 0;
+ }
+@@ -8567,6 +9285,14 @@ mysqld_get_one_option(int optid,
+   case OPT_LOWER_CASE_TABLE_NAMES:
+     lower_case_table_names_used= 1;
+     break;
++#ifdef WITH_WSREP
++  case OPT_WSREP_START_POSITION:
++    wsrep_start_position_init (argument);
++    break;
++  case OPT_WSREP_SST_AUTH:
++    wsrep_sst_auth_init (argument);
++    break;
++#endif
+ #if defined(ENABLED_DEBUG_SYNC)
+   case OPT_DEBUG_SYNC_TIMEOUT:
+     /*
+@@ -8926,6 +9652,31 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
+   else
+     global_system_variables.option_bits&= ~OPTION_BIG_SELECTS;
++#ifdef WITH_WSREP
++  if (global_system_variables.wsrep_causal_reads) {
++      WSREP_WARN("option --wsrep-casual-reads is deprecated");
++      if (!(global_system_variables.wsrep_sync_wait &
++            WSREP_SYNC_WAIT_BEFORE_READ)) {
++          WSREP_WARN("--wsrep-casual-reads=ON takes precedence over --wsrep-sync-wait=%u. "
++                     "WSREP_SYNC_WAIT_BEFORE_READ is on",
++                     global_system_variables.wsrep_sync_wait);
++          global_system_variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ;
++      } else {
++          // they are turned on both.
++      }
++  } else {
++      if (global_system_variables.wsrep_sync_wait &
++          WSREP_SYNC_WAIT_BEFORE_READ) {
++          WSREP_WARN("--wsrep-sync-wait=%u takes precedence over --wsrep-causal-reads=OFF. "
++                     "WSREP_SYNC_WAIT_BEFORE_READ is on",
++                     global_system_variables.wsrep_sync_wait);
++          global_system_variables.wsrep_causal_reads = 1;
++      } else {
++          // they are turned off both.
++      }
++  }
++#endif // WITH_WSREP
++
+   // Synchronize @@global.autocommit on --autocommit
+   const ulonglong turn_bit_on= opt_autocommit ?
+     OPTION_AUTOCOMMIT : OPTION_NOT_AUTOCOMMIT;
+@@ -9320,6 +10071,9 @@ void refresh_status(THD *thd)
+   /* Reset some global variables */
+   reset_status_vars();
++#ifdef WITH_WSREP
++  wsrep->stats_reset(wsrep);
++#endif /* WITH_WSREP */
+   /* Reset the counters of all key caches (default and named). */
+   process_key_caches(reset_key_cache_counters);
+@@ -9383,6 +10137,12 @@ PSI_mutex_key
+   key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data,
+   key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count,
+   key_LOCK_log_throttle_qni;
++#ifdef WITH_WSREP
++PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd, 
++  key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst, 
++  key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init, 
++  key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync;
++#endif
+ PSI_mutex_key key_LOCK_thd_remove;
+ PSI_mutex_key key_RELAYLOG_LOCK_commit;
+ PSI_mutex_key key_RELAYLOG_LOCK_commit_queue;
+@@ -9468,6 +10228,18 @@ static PSI_mutex_info all_server_mutexes[]=
+   { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL},
+   { &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
+   { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
++#ifdef WITH_WSREP
++  { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0},
++  { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0},
++  { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL},
++  { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL},
++#endif
+   { &key_LOCK_thd_remove, "LOCK_thd_remove", PSI_FLAG_GLOBAL},
+   { &key_LOCK_log_throttle_qni, "LOCK_log_throttle_qni", PSI_FLAG_GLOBAL},
+   { &key_gtid_ensure_index_mutex, "Gtid_state", PSI_FLAG_GLOBAL},
+@@ -9523,6 +10295,12 @@ PSI_cond_key key_BINLOG_update_cond,
+   key_cond_slave_parallel_worker,
+   key_TABLE_SHARE_cond, key_user_level_lock_cond,
+   key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache;
++#ifdef WITH_WSREP
++PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd, 
++  key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst,
++  key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread;
++
++#endif /* WITH_WSREP */
+ PSI_cond_key key_RELAYLOG_update_cond;
+ PSI_cond_key key_BINLOG_COND_done;
+ PSI_cond_key key_RELAYLOG_COND_done;
+@@ -9567,6 +10345,15 @@ static PSI_cond_info all_server_conds[]=
+   { &key_user_level_lock_cond, "User_level_lock::cond", 0},
+   { &key_COND_thread_count, "COND_thread_count", PSI_FLAG_GLOBAL},
+   { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL},
++#ifdef WITH_WSREP
++  { &key_COND_wsrep_ready, "COND_wsrep_ready", PSI_FLAG_GLOBAL},
++  { &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL},
++  { &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL},
++  { &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0},
++  { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL},
++  { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0},
++  { &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL},
++#endif
+   { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL},
+   { &key_gtid_ensure_index_cond, "Gtid_state", PSI_FLAG_GLOBAL}
+ };
+diff --git a/sql/mysqld.h b/sql/mysqld.h
+index 2844275..17b601a 100644
+--- a/sql/mysqld.h
++++ b/sql/mysqld.h
+@@ -65,7 +65,11 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
+                                            some places */
+ /* Function prototypes */
+ void kill_mysql(void);
++#ifdef WITH_WSREP
++void close_connection(THD *thd, uint sql_errno= 0, bool lock=1);
++#else
+ void close_connection(THD *thd, uint sql_errno= 0);
++#endif
+ void handle_connection_in_main_thread(THD *thd);
+ void create_thread_to_handle_connection(THD *thd);
+ void destroy_thd(THD *thd);
+@@ -309,6 +313,10 @@ extern pthread_key(MEM_ROOT**,THR_MALLOC);
+ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
+        key_LOCK_pool;
+ #endif /* HAVE_MMAP */
++#ifdef WITH_WSREP
++extern PSI_mutex_key key_LOCK_wsrep_thd;
++extern PSI_cond_key  key_COND_wsrep_thd;
++#endif /* HAVE_WSREP */
+ #ifdef HAVE_OPENSSL
+ extern PSI_mutex_key key_LOCK_des_key_file;
+@@ -658,6 +666,14 @@ enum options_mysqld
+   OPT_WANT_CORE,
+   OPT_ENGINE_CONDITION_PUSHDOWN,
+   OPT_LOG_ERROR,
++#ifdef WITH_WSREP
++  OPT_WSREP_PROVIDER,
++  OPT_WSREP_PROVIDER_OPTIONS,
++  OPT_WSREP_CLUSTER_ADDRESS,
++  OPT_WSREP_START_POSITION,
++  OPT_WSREP_SST_AUTH,
++  OPT_WSREP_RECOVER,
++#endif /* WITH_WSREP */
+   OPT_MAX_LONG_DATA_SIZE,
+   OPT_PLUGIN_LOAD,
+   OPT_PLUGIN_LOAD_ADD,
+@@ -766,4 +782,9 @@ inline THD *_current_thd(void)
+ extern const char *MY_BIND_ALL_ADDRESSES;
++#ifdef WITH_WSREP
++#include "my_pthread.h"
++pthread_handler_t start_wsrep_THD(void*);
++#endif /* WITH_WSREP */
++
+ #endif /* MYSQLD_INCLUDED */
+diff --git a/sql/protocol.cc b/sql/protocol.cc
+index c03d78b..8e6ba54 100644
+--- a/sql/protocol.cc
++++ b/sql/protocol.cc
+@@ -485,6 +485,14 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
+ void Protocol::end_statement()
+ {
++#ifdef WITH_WSREP
++  /*sanity check, can be removed before 1.0 release */
++  if (WSREP(thd) && thd->wsrep_conflict_state== REPLAYING)
++    {
++      WSREP_ERROR("attempting net_end_statement while replaying");
++      return;
++    }
++#endif
+   DBUG_ENTER("Protocol::end_statement");
+   DBUG_ASSERT(! thd->get_stmt_da()->is_sent());
+   bool error= FALSE;
+diff --git a/sql/rpl_gtid_cache.cc b/sql/rpl_gtid_cache.cc
+index 271a99d..7e8a368 100644
+--- a/sql/rpl_gtid_cache.cc
++++ b/sql/rpl_gtid_cache.cc
+@@ -147,7 +147,22 @@ enum_return_status Group_cache::generate_automatic_gno(THD *thd)
+         else
+         {
+           automatic_type= GTID_GROUP;
++#ifdef WITH_WSREP
++          /*
++            Replace sidno with wsrep_sidno
++            if transaction went through wsrep commit
++          */
++          if (WSREP(thd) && thd->wsrep_trx_meta.gtid.seqno != -1)
++          {
++            automatic_gtid.sidno= wsrep_sidno;
++          }
++          else
++          {
++#endif /* WITH_WSREP */
+           automatic_gtid.sidno= gtid_state->get_server_sidno();
++#ifdef WITH_WSREP
++          }
++#endif /* WITH_WSREP */
+           gtid_state->lock_sidno(automatic_gtid.sidno);
+           automatic_gtid.gno=
+             gtid_state->get_automatic_gno(automatic_gtid.sidno);
+diff --git a/sql/rpl_slave.cc b/sql/rpl_slave.cc
+index 736d790..af86bec 100644
+--- a/sql/rpl_slave.cc
++++ b/sql/rpl_slave.cc
+@@ -55,6 +55,9 @@
+ #include "rpl_rli_pdb.h"
+ #include "global_threads.h"
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif
+ #ifdef HAVE_REPLICATION
+ #include "rpl_tblmap.h"
+@@ -3704,6 +3707,94 @@ apply_event_and_update_pos(Log_event** ptr_ev, THD* thd, Relay_log_info* rli)
+                        rli->mts_recovery_index));
+   }
+ #endif
++#ifdef WITH_WSREP
++  if (wsrep_preordered_opt && WSREP_ON &&
++      (ev->get_type_code() == QUERY_EVENT ||
++       ev->get_type_code() == XID_EVENT ||
++       ev->get_type_code() == TABLE_MAP_EVENT ||
++       ev->get_type_code() == WRITE_ROWS_EVENT ||
++       ev->get_type_code() == UPDATE_ROWS_EVENT ||
++       ev->get_type_code() == DELETE_ROWS_EVENT ||
++       ev->get_type_code() == GTID_LOG_EVENT))
++  {
++    if (ev->get_type_code() == GTID_LOG_EVENT)
++    {
++      thd->wsrep_po_sid= *((Gtid_log_event*)ev)->get_sid();
++    }
++    wsrep_status_t err;
++    if (thd->wsrep_po_cnt == 0)
++    {
++      /* First event in write set, write format description event
++         as a write set header so that the receiver will know how
++         to interpret following events. */
++      Log_event* fde= rli->get_rli_description_event();
++      ulong len= uint4korr(fde->temp_buf + EVENT_LEN_OFFSET);
++      wsrep_buf_t data= {fde->temp_buf, len};
++      if ((err= wsrep->preordered_collect(
++               wsrep, &thd->wsrep_po_handle, &data, 1, true)) != WSREP_OK)
++      {
++        WSREP_ERROR("wsrep preordered collect failed: %d", err);
++        if (err == WSREP_TRX_FAIL &&
++            wsrep->preordered_commit(wsrep, &thd->wsrep_po_handle, NULL,
++                                     0, 0, false))
++        {
++          WSREP_WARN("failed to cancel preordered write set");
++        }
++        DBUG_RETURN(SLAVE_APPLY_EVENT_AND_UPDATE_POS_APPLY_ERROR);
++      }
++    }
++    ++thd->wsrep_po_cnt;
++    ulong len= uint4korr(ev->temp_buf + EVENT_LEN_OFFSET);
++    wsrep_buf_t data= {ev->temp_buf, len};
++    if ((err= wsrep->preordered_collect(wsrep, &thd->wsrep_po_handle,
++                                        &data, 1, 1)) != WSREP_OK)
++    {
++      WSREP_ERROR("wsrep preordered collect failed: %d", err);
++      DBUG_RETURN(SLAVE_APPLY_EVENT_AND_UPDATE_POS_APPLY_ERROR);
++    }
++
++    if (ev->get_type_code() == QUERY_EVENT &&
++        ((Query_log_event*)ev)->starts_group())
++    {
++      thd->wsrep_po_in_trans= TRUE;
++    }
++    else if (ev->get_type_code() == XID_EVENT ||
++             (ev->get_type_code() == QUERY_EVENT &&
++              (thd->wsrep_po_in_trans == FALSE ||
++               ((Query_log_event*)ev)->ends_group())))
++    {
++      int flags= WSREP_FLAG_COMMIT | (thd->wsrep_po_in_trans == FALSE ?
++                                      WSREP_FLAG_ISOLATION : 0);
++      thd->wsrep_po_in_trans= FALSE;
++      thd->wsrep_po_cnt= 0;
++      wsrep_uuid_t source;
++      memcpy(source.data, thd->wsrep_po_sid.bytes, sizeof(source.data));
++      if ((err= wsrep->preordered_commit(wsrep, &thd->wsrep_po_handle,
++                                         &source, flags, 1, true)) != WSREP_OK)
++      {
++        WSREP_ERROR("failed to commit preordered event: %d", err);
++        DBUG_RETURN(SLAVE_APPLY_EVENT_AND_UPDATE_POS_APPLY_ERROR);
++      }
++    }
++    reason= Log_event::EVENT_SKIP_IGNORE;
++    skip_event= TRUE;
++  }
++  else if (WSREP_ON && (ev->get_type_code() == XID_EVENT ||
++      (ev->get_type_code() == QUERY_EVENT && thd->wsrep_mysql_replicated > 0 &&
++       (!strncasecmp(((Query_log_event*)ev)->query , "BEGIN", 5) ||
++        !strncasecmp(((Query_log_event*)ev)->query , "COMMIT", 6) ))))
++  {
++    if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
++    {
++      WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
++      reason = Log_event::EVENT_SKIP_IGNORE;
++    }
++    else
++    {
++      thd->wsrep_mysql_replicated = 0;
++    }
++  }
++#endif /* WITH_WSREP */
+   if (reason == Log_event::EVENT_SKIP_COUNT)
+   {
+     sql_slave_skip_counter= --rli->slave_skip_counter;
+@@ -5825,6 +5916,9 @@ pthread_handler_t handle_slave_sql(void *arg)
+   my_off_t saved_log_pos= 0;
+   my_off_t saved_master_log_pos= 0;
+   my_off_t saved_skip= 0;
++#ifdef WITH_WSREP
++  my_bool wsrep_node_dropped= FALSE;
++#endif /* WITH_WSREP */
+   Relay_log_info* rli = ((Master_info*)arg)->rli;
+   const char *errmsg;
+@@ -5833,6 +5927,9 @@ pthread_handler_t handle_slave_sql(void *arg)
+   // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
+   my_thread_init();
+   DBUG_ENTER("handle_slave_sql");
++#ifdef WITH_WSREP
++ wsrep_restart_point:
++#endif /* WITH_WSREP */
+   DBUG_ASSERT(rli->inited);
+   mysql_mutex_lock(&rli->run_lock);
+@@ -5976,6 +6073,18 @@ pthread_handler_t handle_slave_sql(void *arg)
+   }
+ #endif
++#ifdef WITH_WSREP
++  thd->wsrep_exec_mode= LOCAL_STATE;
++  /* synchronize with wsrep replication */
++  if (WSREP_ON)
++  {
++    thd->wsrep_po_handle= WSREP_PO_INITIALIZER;
++    thd->wsrep_po_cnt= 0;
++    thd->wsrep_po_in_trans= FALSE;
++    memset(&thd->wsrep_po_sid, 0, sizeof(thd->wsrep_po_sid));
++    wsrep_ready_wait();
++  }
++#endif
+   DBUG_PRINT("master_info",("log_file_name: %s  position: %s",
+                             rli->get_group_master_log_name(),
+                             llstr(rli->get_group_master_log_pos(),llbuff)));
+@@ -6118,6 +6227,12 @@ Error running query, slave SQL thread aborted. Fix the problem, and restart \
+ the slave SQL thread with \"SLAVE START\". We stopped at log \
+ '%s' position %s", rli->get_rpl_log_name(),
+ llstr(rli->get_group_master_log_pos(), llbuff));
++#ifdef WITH_WSREP
++        if (WSREP_ON && last_errno == ER_UNKNOWN_COM_ERROR)
++        {
++        wsrep_node_dropped= TRUE;
++      }
++#endif /* WITH_WSREP */
+       }
+       goto err;
+     }
+@@ -6139,6 +6254,16 @@ llstr(rli->get_group_master_log_pos(), llbuff));
+     rli->recovery_groups_inited= false;
+   }
++#ifdef WITH_WSREP
++  if (WSREP_ON)
++  {
++    if (wsrep->preordered_commit(wsrep, &thd->wsrep_po_handle,
++                                 NULL, 0, 0, false))
++    {
++      WSREP_WARN("preordered cleanup failed");
++    }
++  }
++#endif /* WITH_WSREP */
+   /*
+     Some events set some playgrounds, which won't be cleared because thread
+     stops. Stopping of this thread may not be known to these events ("stop"
+@@ -6191,6 +6316,27 @@ llstr(rli->get_group_master_log_pos(), llbuff));
+   if (thd_added)
+     remove_global_thread(thd);
+   delete thd;
++#ifdef WITH_WSREP
++  /* if slave stopped due to node going non primary, we set global flag to
++     trigger automatic restart of slave when node joins back to cluster
++  */
++   if (wsrep_node_dropped && wsrep_restart_slave)
++   {
++     if (wsrep_ready)
++     {
++       WSREP_INFO("Slave error due to node temporarily non-primary"
++                "SQL slave will continue");
++       wsrep_node_dropped= FALSE;
++       mysql_mutex_unlock(&rli->run_lock);
++       goto wsrep_restart_point;
++     } else {
++       WSREP_INFO("Slave error due to node going non-primary");
++       WSREP_INFO("wsrep_restart_slave was set and therefore slave will be "
++                "automatically restarted when node joins back to cluster");
++       wsrep_restart_slave_activated= TRUE;
++     }
++   }
++#endif /* WITH_WSREP */
+  /*
+   Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
+   is important. Otherwise a killer_thread can execute between the calls and
+diff --git a/sql/set_var.h b/sql/set_var.h
+index fbc7e16..6995619 100644
+--- a/sql/set_var.h
++++ b/sql/set_var.h
+@@ -256,6 +256,9 @@ public:
+   int check(THD *thd);
+   int update(THD *thd);
+   int light_check(THD *thd);
++#ifdef WITH_WSREP
++  int wsrep_store_variable(THD *thd);
++#endif
+   void print(THD *thd, String *str);  /* To self-print */
+ #ifdef OPTIMIZER_TRACE
+   virtual bool is_var_optimizer_trace() const
+@@ -354,6 +357,9 @@ extern sys_var *Sys_gtid_purged_ptr;
+ const CHARSET_INFO *get_old_charset_by_name(const char *old_name);
++#ifdef WITH_WSREP
++int sql_set_wsrep_variables(THD *thd, List<set_var_base> *var_list);
++#endif
+ int sys_var_init();
+ int sys_var_add_options(std::vector<my_option> *long_options, int parse_flags);
+ void sys_var_end(void);
+diff --git a/sql/sp.cc b/sql/sp.cc
+index 915a6af..d52a5ee 100644
+--- a/sql/sp.cc
++++ b/sql/sp.cc
+@@ -2734,3 +2734,37 @@ String *sp_get_item_value(THD *thd, Item *item, String *str)
+     return NULL;
+   }
+ }
++#ifdef WITH_WSREP
++int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
++{
++  String log_query;
++  sp_head *sp = thd->lex->sphead;
++  ulong saved_mode= thd->variables.sql_mode;
++  String retstr(64);
++  retstr.set_charset(system_charset_info);
++
++  log_query.set_charset(system_charset_info);
++
++  if (sp->m_type == TYPE_ENUM_FUNCTION)
++  {
++    sp_returns_type(thd, retstr, sp);
++  }
++
++  if (!create_string(thd, &log_query,
++                     sp->m_type,
++                     (sp->m_explicit_name ? sp->m_db.str : NULL), 
++                     (sp->m_explicit_name ? sp->m_db.length : 0), 
++                     sp->m_name.str, sp->m_name.length,
++                     sp->m_params.str, sp->m_params.length,
++                     retstr.c_ptr(), retstr.length(),
++                     sp->m_body.str, sp->m_body.length,
++                     sp->m_chistics, &(thd->lex->definer->user),
++                     &(thd->lex->definer->host),
++                     saved_mode))
++  {
++    WSREP_WARN("SP create string failed: %s", thd->query());
++    return 1;
++  }
++  return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
++}
++#endif /* WITH_WSREP */
+diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
+index dc059b0..524b764 100644
+--- a/sql/sql_acl.cc
++++ b/sql/sql_acl.cc
+@@ -2304,6 +2304,9 @@ int check_change_password(THD *thd, const char *host, const char *user,
+     return(1);
+   }
+   if (!thd->slave_thread &&
++#ifdef WITH_WSREP
++      (!WSREP(thd) || !thd->wsrep_applier) &&
++#endif /* WITH_WSREP */
+       (strcmp(thd->security_ctx->user, user) ||
+        my_strcasecmp(system_charset_info, host,
+                      thd->security_ctx->priv_host)))
+@@ -2311,7 +2314,12 @@ int check_change_password(THD *thd, const char *host, const char *user,
+     if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0))
+       return(1);
+   }
++#ifdef WITH_WSREP
++  if ((!WSREP(thd) || !thd->wsrep_applier) &&
++      !thd->slave_thread && !thd->security_ctx->user[0])
++#else
+   if (!thd->slave_thread && !thd->security_ctx->user[0])
++#endif /* WITH_WSREP */
+   {
+     my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
+                MYF(0));
+@@ -2392,7 +2400,7 @@ bool change_password(THD *thd, const char *host, const char *user,
+   TABLE *table;
+   /* Buffer should be extended when password length is extended. */
+   char buff[512];
+-  ulong query_length;
++  ulong query_length=0;
+   bool save_binlog_row_based;
+   uchar user_key[MAX_KEY_LENGTH];
+   char *plugin_temp= NULL;
+@@ -2400,6 +2408,9 @@ bool change_password(THD *thd, const char *host, const char *user,
+   uint new_password_len= (uint) strlen(new_password);
+   bool result= 1;
+   enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD;
++#ifdef WITH_WSREP
++  const CSET_STRING query_save = thd->query_string;
++#endif /* WITH_WSREP */
+   DBUG_ENTER("change_password");
+   DBUG_PRINT("enter",("host: '%s'  user: '%s'  new_password: '%s'",
+                     host,user,new_password));
+@@ -2407,6 +2418,18 @@ bool change_password(THD *thd, const char *host, const char *user,
+   if (check_change_password(thd, host, user, new_password, new_password_len))
+     DBUG_RETURN(1);
++#ifdef WITH_WSREP
++  if (WSREP(thd) && !thd->wsrep_applier)
++  {
++      query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
++                          user ? user : "",
++                          host ? host : "",
++                          new_password);
++    thd->set_query_inner(buff, query_length, system_charset_info);
++
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
++  }
++#endif /* WITH_WSREP */
+   tables.init_one_table("mysql", 5, "user", 4, "user", TL_WRITE);
+@@ -2677,13 +2700,26 @@ bool change_password(THD *thd, const char *host, const char *user,
+                         table->file->has_transactions());
+ end:
+   result|= acl_trans_commit_and_close_tables(thd);
++#ifdef WITH_WSREP
++  if (WSREP(thd) && !thd->wsrep_applier)
++  {
++    WSREP_TO_ISOLATION_END;
++    thd->query_string     = query_save;
++    thd->wsrep_exec_mode  = LOCAL_STATE;
++  }
++#endif /* WITH_WSREP */
+   /* Restore the state of binlog format */
+   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+   if (save_binlog_row_based)
+     thd->set_current_stmt_binlog_format_row();
+   DBUG_RETURN(result);
++#ifdef WITH_WSREP
++  error:
++  WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff);
++  DBUG_RETURN(result);
++#endif /* WITH_WSREP */
+ }
+@@ -10114,6 +10150,12 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
+     if (mpvio->charset_adapter->init_client_charset(uint2korr(ptr)))
+       DBUG_RETURN(1);
+   }
++  else
++  {
++    sql_print_warning("Client failed to provide its character set. "
++                      "'%s' will be used as client character set.",
++                      mpvio->charset_adapter->charset()->csname);
++  }
+   /* Convert database and user names to utf8 */
+   db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
+diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
+index 52b7ff4..7b53fa6 100644
+--- a/sql/sql_admin.cc
++++ b/sql/sql_admin.cc
+@@ -1124,6 +1124,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
+   if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
+                          FALSE, UINT_MAX, FALSE))
+     goto error; /* purecov: inspected */
++  WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
+   thd->enable_slow_log= opt_log_slow_admin_statements;
+   res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
+     mysql_recreate_table(thd, first_table, true) :
+@@ -1156,6 +1157,7 @@ bool Sql_cmd_repair_table::execute(THD *thd)
+                          FALSE, UINT_MAX, FALSE))
+     goto error; /* purecov: inspected */
+   thd->enable_slow_log= opt_log_slow_admin_statements;
++  WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
+   res= mysql_admin_table(thd, first_table, &thd->lex->check_opt, "repair",
+                          TL_WRITE, 1,
+                          MY_TEST(thd->lex->check_opt.sql_flags & TT_USEFRM),
+diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
+index 3cf1c93..167daff 100644
+--- a/sql/sql_alter.cc
++++ b/sql/sql_alter.cc
+@@ -18,6 +18,9 @@
+                                              // mysql_exchange_partition
+ #include "sql_base.h"                        // open_temporary_tables
+ #include "sql_alter.h"
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif /* WITH_WSREP */
+ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
+@@ -304,6 +307,17 @@ bool Sql_cmd_alter_table::execute(THD *thd)
+   thd->enable_slow_log= opt_log_slow_admin_statements;
++#ifdef WITH_WSREP
++  TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
++
++  if ((!thd->is_current_stmt_binlog_format_row() ||
++       !find_temporary_table(thd, first_table)))
++    {
++      WSREP_TO_ISOLATION_BEGIN(((lex->name.str) ? select_lex->db : NULL),
++                             ((lex->name.str) ? lex->name.str : NULL),
++                             first_table);
++    }
++#endif /* WITH_WSREP */
+   result= mysql_alter_table(thd, select_lex->db, lex->name.str,
+                             &create_info,
+                             first_table,
+@@ -313,6 +327,13 @@ bool Sql_cmd_alter_table::execute(THD *thd)
+                             lex->ignore);
+   DBUG_RETURN(result);
++#ifdef WITH_WSREP
++ error:
++  {
++    WSREP_WARN("ALTER TABLE isolation failure");
++    DBUG_RETURN(TRUE);
++  }
++#endif /* WITH_WSREP */
+ }
+diff --git a/sql/sql_base.cc b/sql/sql_base.cc
+index ef5e7dc..a325273 100644
+--- a/sql/sql_base.cc
++++ b/sql/sql_base.cc
+@@ -57,6 +57,9 @@
+ #include <io.h>
+ #endif
+ #include "table_cache.h" // Table_cache_manager, Table_cache
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif /* WITH_WSREP */
+ bool
+@@ -5229,6 +5232,22 @@ restart:
+         goto err;
+       }
+     }
++#ifdef WITH_WSREP
++  if ((thd->lex->sql_command== SQLCOM_INSERT         ||
++       thd->lex->sql_command== SQLCOM_INSERT_SELECT  ||
++       thd->lex->sql_command== SQLCOM_REPLACE        ||
++       thd->lex->sql_command== SQLCOM_REPLACE_SELECT ||
++       thd->lex->sql_command== SQLCOM_UPDATE         ||
++       thd->lex->sql_command== SQLCOM_UPDATE_MULTI   ||
++       thd->lex->sql_command== SQLCOM_LOAD           ||
++       thd->lex->sql_command== SQLCOM_DELETE)        &&
++      wsrep_replicate_myisam                         &&
++      (*start)->table && (*start)->table->file->ht->db_type == DB_TYPE_MYISAM)
++    {
++      WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start));
++    }
++ error:
++#endif
+     /* Set appropriate TABLE::lock_type. */
+     if (tbl && tables->lock_type != TL_UNLOCK && 
+diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
+index cf7006f..a89bd06 100644
+--- a/sql/sql_builtin.cc.in
++++ b/sql/sql_builtin.cc.in
+@@ -23,7 +23,11 @@ extern "C"
+ extern
+ #endif
+ builtin_plugin 
+-  @mysql_mandatory_plugins@ @mysql_optional_plugins@ builtin_binlog_plugin, builtin_mysql_password_plugin;
++      @mysql_mandatory_plugins@ @mysql_optional_plugins@ builtin_binlog_plugin,
++#ifdef WITH_WSREP
++      builtin_wsrep_plugin@mysql_plugin_defs@,
++#endif /* WITH_WSREP */
++      builtin_mysql_password_plugin;
+ struct st_mysql_plugin *mysql_optional_plugins[]=
+ {
+@@ -32,5 +36,9 @@ struct st_mysql_plugin *mysql_optional_plugins[]=
+ struct st_mysql_plugin *mysql_mandatory_plugins[]=
+ {
+-  builtin_binlog_plugin, builtin_mysql_password_plugin, @mysql_mandatory_plugins@ 0
++  builtin_binlog_plugin,
++#ifdef WITH_WSREP
++  builtin_wsrep_plugin@mysql_plugin_defs@,
++#endif /* WITH_WSREP */
++  builtin_mysql_password_plugin, @mysql_mandatory_plugins@ 0
+ };
+diff --git a/sql/sql_class.cc b/sql/sql_class.cc
+index 79d56ad..cc35779 100644
+--- a/sql/sql_class.cc
++++ b/sql/sql_class.cc
+@@ -57,6 +57,10 @@
+ #include "debug_sync.h"
+ #include "sql_parse.h"                          // is_update_query
+ #include "sql_callback.h"
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#include "wsrep_thd.h"
++#endif
+ #include "lock.h"
+ #include "global_threads.h"
+ #include "mysqld.h"
+@@ -816,6 +820,176 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
+   return buffer;
+ }
++#ifdef WITH_WSREP
++extern int wsrep_on(void *thd)
++{
++  return (int)(WSREP(((THD*)thd)));
++}
++extern "C" bool wsrep_thd_is_wsrep_on(THD *thd)
++{
++  return thd->variables.wsrep_on;
++}
++
++extern "C" bool wsrep_consistency_check(void *thd)
++{
++  return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
++}
++
++extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode)
++{
++  thd->wsrep_exec_mode= mode;
++}
++extern "C" void wsrep_thd_set_query_state(
++      THD *thd, enum wsrep_query_state state)
++{
++  thd->wsrep_query_state= state;
++}
++extern "C" void wsrep_thd_set_conflict_state(
++      THD *thd, enum wsrep_conflict_state state)
++{
++  thd->wsrep_conflict_state= state;
++}
++
++
++extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd)
++{
++  return thd->wsrep_exec_mode;
++}
++
++extern "C" const char *wsrep_thd_exec_mode_str(THD *thd)
++{
++  return 
++    (!thd) ? "void" :
++    (thd->wsrep_exec_mode == LOCAL_STATE)  ? "local"         :
++    (thd->wsrep_exec_mode == REPL_RECV)    ? "applier"       :
++    (thd->wsrep_exec_mode == TOTAL_ORDER)  ? "total order"   : 
++    (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit"  : "void";
++}
++
++extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd)
++{
++  return thd->wsrep_query_state;
++}
++
++extern "C" const char *wsrep_thd_query_state_str(THD *thd)
++{
++  return 
++    (!thd) ? "void" : 
++    (thd->wsrep_query_state == QUERY_IDLE)        ? "idle"          :
++    (thd->wsrep_query_state == QUERY_EXEC)        ? "executing"     :
++    (thd->wsrep_query_state == QUERY_COMMITTING)  ? "committing"    :
++    (thd->wsrep_query_state == QUERY_EXITING)     ? "exiting"       : 
++    (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back"  : "void";
++}
++
++extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd)
++{
++  return thd->wsrep_conflict_state;
++}
++extern "C" const char *wsrep_thd_conflict_state_str(THD *thd)
++{
++  return 
++    (!thd) ? "void" :
++    (thd->wsrep_conflict_state == NO_CONFLICT)      ? "no conflict"  :
++    (thd->wsrep_conflict_state == MUST_ABORT)       ? "must abort"   :
++    (thd->wsrep_conflict_state == ABORTING)         ? "aborting"     :
++    (thd->wsrep_conflict_state == MUST_REPLAY)      ? "must replay"  : 
++    (thd->wsrep_conflict_state == REPLAYING)        ? "replaying"    : 
++    (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying"     : 
++    (thd->wsrep_conflict_state == CERT_FAILURE)     ? "cert failure" : "void";
++}
++
++extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
++{
++  return &thd->wsrep_ws_handle;
++}
++
++extern "C"void wsrep_thd_LOCK(THD *thd)
++{
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++}
++extern "C"void wsrep_thd_UNLOCK(THD *thd)
++{
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++}
++extern "C" time_t wsrep_thd_query_start(THD *thd) 
++{
++  return thd->query_start();
++}
++extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) 
++{
++  return thd->wsrep_rand;
++}
++extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) 
++{
++  return thd->thread_id;
++}
++extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) 
++{
++  return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED;
++}
++extern "C" query_id_t wsrep_thd_query_id(THD *thd) 
++{
++  return thd->query_id;
++}
++extern "C" char *wsrep_thd_query(THD *thd) 
++{
++  return (thd) ? thd->query() : NULL;
++}
++extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd) 
++{
++  return thd->wsrep_last_query_id;
++}
++extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id) 
++{
++  thd->wsrep_last_query_id= id;
++}
++extern "C" void wsrep_thd_awake(THD *thd, my_bool signal)
++{
++  if (signal)
++  {
++    mysql_mutex_lock(&thd->LOCK_thd_data);
++    thd->awake(THD::KILL_QUERY);
++    mysql_mutex_unlock(&thd->LOCK_thd_data);
++  }
++  else
++  {
++    mysql_mutex_lock(&LOCK_wsrep_replaying);
++    mysql_cond_broadcast(&COND_wsrep_replaying);
++    mysql_mutex_unlock(&LOCK_wsrep_replaying);
++  }
++}
++extern "C" int wsrep_thd_retry_counter(THD *thd) 
++{
++  return(thd->wsrep_retry_counter);
++}
++
++extern int
++wsrep_trx_order_before(void *thd1, void *thd2)
++{
++    if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) {
++        WSREP_DEBUG("BF conflict, order: %lld %lld\n",
++                    (long long)wsrep_thd_trx_seqno((THD*)thd1),
++                    (long long)wsrep_thd_trx_seqno((THD*)thd2));
++        return 1;
++    }
++    WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
++                (long long)wsrep_thd_trx_seqno((THD*)thd1),
++                (long long)wsrep_thd_trx_seqno((THD*)thd2));
++    return 0;
++}
++extern "C" int
++wsrep_trx_is_aborting(void *thd_ptr)
++{
++      if (thd_ptr) {
++              if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) ||
++                  (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) {
++                return 1;
++              }
++      }
++      return 0;
++}
++#endif
+ /**
+   Implementation of Drop_table_error_handler::handle_condition().
+@@ -843,7 +1017,6 @@ bool Drop_table_error_handler::handle_condition(THD *thd,
+           sql_errno == ER_TRG_NO_DEFINER);
+ }
+-
+ void Open_tables_state::set_open_tables_state(Open_tables_state *state)
+ {
+   this->open_tables= state->open_tables;
+@@ -878,7 +1051,11 @@ void Open_tables_state::reset_open_tables_state()
+ }
++#ifdef WITH_WSREP
++THD::THD(bool enable_plugins, bool is_applier)
++#else
+ THD::THD(bool enable_plugins)
++#endif
+    :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
+               /* statement id */ 0),
+    rli_fake(0), rli_slave(NULL),
+@@ -911,6 +1088,16 @@ THD::THD(bool enable_plugins)
+    bootstrap(0),
+    derived_tables_processing(FALSE),
+    sp_runtime_ctx(NULL),
++#ifdef WITH_WSREP
++   wsrep_applier(is_applier),
++   wsrep_applier_closing(FALSE),
++   wsrep_client_thread(0),
++   wsrep_po_handle(WSREP_PO_INITIALIZER),
++   wsrep_po_cnt(0),
++   wsrep_po_in_trans(FALSE),
++   wsrep_apply_format(0),
++   wsrep_apply_toi(false),
++#endif
+    m_parser_state(NULL),
+ #if defined(ENABLED_DEBUG_SYNC)
+    debug_sync_control(0),
+@@ -1001,6 +1188,22 @@ THD::THD(bool enable_plugins)
+   *scramble= '\0';
+   skip_gtid_rollback= false;
++#ifdef WITH_WSREP
++  mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST);
++  mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL);
++  wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID;
++  wsrep_ws_handle.opaque = NULL;
++  wsrep_retry_counter     = 0;
++  wsrep_PA_safe           = true;
++  wsrep_retry_query       = NULL;
++  wsrep_retry_query_len   = 0;
++  wsrep_retry_command     = COM_CONNECT;
++  wsrep_consistency_check = NO_CONSISTENCY_CHECK;
++  wsrep_status_vars       = 0;
++  wsrep_mysql_replicated  = 0;
++  wsrep_TOI_pre_query     = NULL;
++  wsrep_TOI_pre_query_len = 0;
++#endif
+   /* Call to init() below requires fully initialized Open_tables_state. */
+   reset_open_tables_state();
+@@ -1033,6 +1236,13 @@ THD::THD(bool enable_plugins)
+   randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
+   substitute_null_with_insert_id = FALSE;
+   thr_lock_info_init(&lock_info); /* safety: will be reset after start */
++#ifdef WITH_WSREP
++  lock_info.mysql_thd= (void *)this;
++  lock_info.in_lock_tables= false;
++#ifdef WSREP_PROC_INFO
++  wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
++#endif /* WSREP_PROC_INFO */
++#endif /* WITH_WSREP */
+   m_internal_handler= NULL;
+   m_binlog_invoker= FALSE;
+@@ -1379,6 +1589,22 @@ void THD::init(void)
+   reset_current_stmt_binlog_format_row();
+   reset_binlog_local_stmt_filter();
+   memset(&status_var, 0, sizeof(status_var));
++#ifdef WITH_WSREP
++  wsrep_exec_mode= wsrep_applier ? REPL_RECV :  LOCAL_STATE;
++  wsrep_conflict_state= NO_CONFLICT;
++  wsrep_query_state= QUERY_IDLE;
++  wsrep_last_query_id= 0;
++  wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
++  wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
++  wsrep_converted_lock_session= false;
++  wsrep_retry_counter= 0;
++  wsrep_rli= NULL;
++  wsrep_PA_safe= true;
++  wsrep_consistency_check = NO_CONSISTENCY_CHECK;
++  wsrep_mysql_replicated  = 0;
++  wsrep_TOI_pre_query     = NULL;
++  wsrep_TOI_pre_query_len = 0;
++#endif
+   binlog_row_event_extra_data= 0;
+   if (variables.sql_log_bin)
+@@ -1573,6 +1799,13 @@ void THD::release_resources()
+     plugin_thdvar_cleanup(this);
+   m_release_resources_done= true;
++#ifdef WITH_WSREP
++  mysql_mutex_lock(&LOCK_wsrep_thd);
++  mysql_mutex_unlock(&LOCK_wsrep_thd);
++  mysql_mutex_destroy(&LOCK_wsrep_thd);
++  if (wsrep_rli) delete wsrep_rli;
++  if (wsrep_status_vars) wsrep->stats_free(wsrep, wsrep_status_vars);
++#endif
+ }
+@@ -1873,7 +2106,19 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
+         (e.g. see partitioning code).
+       */
+       if (!thd_table->needs_reopen())
++#ifdef WITH_WSREP
++      {
++      signalled|= mysql_lock_abort_for_thread(this, thd_table);
++      if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) 
++      {
++        WSREP_DEBUG("remove_table_from_cache: %llu",
++                    (unsigned long long) this->real_id);
++        wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
++      }
++      }
++#else
+         signalled|= mysql_lock_abort_for_thread(this, thd_table);
++#endif
+     }
+     mysql_mutex_unlock(&in_use->LOCK_thd_data);
+   }
+@@ -2438,6 +2683,13 @@ bool sql_exchange::escaped_given(void)
+ bool select_send::send_result_set_metadata(List<Item> &list, uint flags)
+ {
+   bool res;
++#ifdef WITH_WSREP
++  if (WSREP(thd) && thd->wsrep_retry_query)
++  {
++    WSREP_DEBUG("skipping select metadata");
++    return FALSE;
++  }
++#endif /* WITH_WSREP */
+   if (!(res= thd->protocol->send_result_set_metadata(&list, flags)))
+     is_result_set_started= 1;
+   return res;
+@@ -4206,8 +4458,13 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
+ extern "C" int thd_binlog_format(const MYSQL_THD thd)
+ {
++#ifdef WITH_WSREP
++  if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) &&
++      (thd->variables.option_bits & OPTION_BIN_LOG))
++#else
+   if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
+-    return (int) thd->variables.binlog_format;
++#endif
++    return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
+   else
+     return BINLOG_FORMAT_UNSPEC;
+ }
+diff --git a/sql/sql_class.h b/sql/sql_class.h
+index 17f0055..ded32a5 100644
+--- a/sql/sql_class.h
++++ b/sql/sql_class.h
+@@ -70,6 +70,18 @@ void set_thd_stage_info(void *thd,
+ #define THD_STAGE_INFO(thd, stage) \
+   (thd)->enter_stage(& stage, NULL, __func__, __FILE__, __LINE__)
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++struct wsrep_thd_shadow {
++  ulonglong            options;
++  uint                 server_status;
++  enum wsrep_exec_mode wsrep_exec_mode;
++  Vio                  *vio;
++  ulong                tx_isolation;
++  char                 *db;
++  size_t               db_length;
++};
++#endif
+ class Reprepare_observer;
+ class Relay_log_info;
+@@ -547,6 +559,12 @@ typedef struct system_variables
+   my_bool sysdate_is_now;
+   my_bool binlog_rows_query_log_events;
++#ifdef WITH_WSREP
++  my_bool wsrep_on;
++  my_bool wsrep_causal_reads;
++  uint wsrep_sync_wait;
++  ulong wsrep_retry_autocommit;
++#endif
+   double long_query_time_double;
+   my_bool pseudo_slave_mode;
+@@ -2321,7 +2339,8 @@ public:
+   int is_current_stmt_binlog_format_row() const {
+     DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT ||
+                 current_stmt_binlog_format == BINLOG_FORMAT_ROW);
+-    return current_stmt_binlog_format == BINLOG_FORMAT_ROW;
++    return (WSREP_BINLOG_FORMAT((ulong)current_stmt_binlog_format) ==
++            BINLOG_FORMAT_ROW);
+   }
+   /** Tells whether the given optimizer_switch flag is on */
+   inline bool optimizer_switch_flag(ulonglong flag) const
+@@ -3114,6 +3133,45 @@ public:
+     query_id_t first_query_id;
+   } binlog_evt_union;
++#ifdef WITH_WSREP
++  const bool                wsrep_applier; /* dedicated slave applier thread */
++  bool                      wsrep_applier_closing; /* applier marked to close */
++  bool                      wsrep_client_thread; /* to identify client threads*/
++  enum wsrep_exec_mode      wsrep_exec_mode;
++  query_id_t                wsrep_last_query_id;
++  enum wsrep_query_state    wsrep_query_state;
++  enum wsrep_conflict_state wsrep_conflict_state;
++  mysql_mutex_t             LOCK_wsrep_thd;
++  mysql_cond_t              COND_wsrep_thd;
++  // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
++  // wsrep_seqno_t             wsrep_trx_seqno;
++  wsrep_trx_meta_t          wsrep_trx_meta;
++  uint32                    wsrep_rand;
++  Relay_log_info*           wsrep_rli;
++  bool                      wsrep_converted_lock_session;
++  wsrep_ws_handle_t         wsrep_ws_handle;
++#ifdef WSREP_PROC_INFO
++  char                      wsrep_info[128]; /* string for dynamic proc info */
++#endif /* WSREP_PROC_INFO */
++  ulong                     wsrep_retry_counter; // of autocommit
++  bool                      wsrep_PA_safe;
++  char*                     wsrep_retry_query;
++  size_t                    wsrep_retry_query_len;
++  enum enum_server_command  wsrep_retry_command;
++  enum wsrep_consistency_check_mode 
++                            wsrep_consistency_check;
++  wsrep_stats_var*          wsrep_status_vars;
++  int                       wsrep_mysql_replicated;
++  const char*               wsrep_TOI_pre_query; /* a query to apply before 
++                                                    the actual TOI query */
++  size_t                    wsrep_TOI_pre_query_len;
++  wsrep_po_handle_t         wsrep_po_handle;
++  size_t                    wsrep_po_cnt;
++  my_bool                   wsrep_po_in_trans;
++  rpl_sid                   wsrep_po_sid;
++  void*                     wsrep_apply_format;
++  bool                      wsrep_apply_toi; /* applier processing in TOI */
++#endif /* WITH_WSREP */
+   /**
+     Internal parser state.
+     Note that since the parser is not re-entrant, we keep only one parser
+@@ -3149,7 +3207,11 @@ public:
+   // We don't want to load/unload plugins for unit tests.
+   bool m_enable_plugins;
++#ifdef WITH_WSREP
++  THD(bool enable_plugins= true, bool is_applier = false);
++#else
+   THD(bool enable_plugins= true);
++#endif
+   /*
+     The THD dtor is effectively split in two:
+@@ -3657,7 +3719,7 @@ public:
+       tests fail and so force them to propagate the
+       lex->binlog_row_based_if_mixed upwards to the caller.
+     */
+-    if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
++    if ((WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED)&&
+         (in_sub_stmt == 0))
+       set_current_stmt_binlog_format_row();
+@@ -3699,7 +3761,7 @@ public:
+                 show_system_thread(system_thread)));
+     if (in_sub_stmt == 0)
+     {
+-      if (variables.binlog_format == BINLOG_FORMAT_ROW)
++      if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW)
+         set_current_stmt_binlog_format_row();
+       else if (temporary_tables == NULL)
+         clear_current_stmt_binlog_format_row();
+diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
+index 67b671b..9034a6e 100644
+--- a/sql/sql_connect.cc
++++ b/sql/sql_connect.cc
+@@ -57,6 +57,9 @@ using std::max;
+ #else
+ #define MIN_HANDSHAKE_SIZE      6
+ #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif
+ /*
+   Get structure for logging connection data for the current user
+@@ -706,7 +709,11 @@ bool setup_connection_thread_globals(THD *thd)
+ {
+   if (thd->store_globals())
+   {
++#ifdef WITH_WSREP
++    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#else
+     close_connection(thd, ER_OUT_OF_RESOURCES);
++#endif
+     statistic_increment(aborted_connects,&LOCK_status);
+     MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+     return 1;                                   // Error
+@@ -772,6 +779,17 @@ bool login_connection(THD *thd)
+ void end_connection(THD *thd)
+ {
+   NET *net= &thd->net;
++#ifdef WITH_WSREP
++  if (WSREP(thd))
++  {
++    wsrep_status_t rcode= wsrep->free_connection(wsrep, thd->thread_id);
++    if (rcode) {
++      WSREP_WARN("wsrep failed to free connection context: %lu, code: %d",
++                 thd->thread_id, rcode);
++    }
++  }
++  thd->wsrep_client_thread= 0;
++#endif
+   plugin_thdvar_cleanup(thd);
+   /*
+@@ -912,6 +930,9 @@ bool thd_prepare_connection(THD *thd)
+                          (char *) thd->security_ctx->host_or_ip);
+   prepare_new_connection_state(thd);
++#ifdef WITH_WSREP
++  thd->wsrep_client_thread= 1;
++#endif /* WITH_WSREP */
+   return FALSE;
+ }
+@@ -933,7 +954,11 @@ void do_handle_one_connection(THD *thd_arg)
+   if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
+   {
++#ifdef WITH_WSREP
++    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#else
+     close_connection(thd, ER_OUT_OF_RESOURCES);
++#endif
+     statistic_increment(aborted_connects,&LOCK_status);
+     MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+     return;
+@@ -983,9 +1008,21 @@ void do_handle_one_connection(THD *thd_arg)
+   break;
+     }
+     end_connection(thd);
++#ifdef WITH_WSREP
++  if (WSREP(thd))
++  {
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    thd->wsrep_query_state= QUERY_EXITING;
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++#endif
+ end_thread:
++#ifdef WITH_WSREP
++    close_connection(thd, 0, 1);
++#else
+     close_connection(thd);
++#endif
+     if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
+       return;                                 // Probably no-threads
+diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
+index f3e8876..1b9ef9b 100644
+--- a/sql/sql_delete.cc
++++ b/sql/sql_delete.cc
+@@ -451,7 +451,11 @@ cleanup:
+   /* See similar binlogging code in sql_update.cc, for comments */
+   if ((error < 0) || thd->transaction.stmt.cannot_safely_rollback())
+   {
++#ifdef WITH_WSREP
++    if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()))
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       int errcode= 0;
+       if (error < 0)
+@@ -896,7 +900,11 @@ void multi_delete::abort_result_set()
+     /* 
+        there is only side effects; to binlog with the error
+     */
++#ifdef WITH_WSREP
++    if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+       /* possible error of writing binary log is ignored deliberately */
+@@ -1067,7 +1075,11 @@ bool multi_delete::send_eof()
+   }
+   if ((local_error == 0) || thd->transaction.stmt.cannot_safely_rollback())
+   {
++#ifdef WITH_WSREP
++    if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       int errcode= 0;
+       if (local_error == 0)
+diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
+index 114beaa..3da18a4 100644
+--- a/sql/sql_insert.cc
++++ b/sql/sql_insert.cc
+@@ -1124,7 +1124,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
+         thd->transaction.stmt.cannot_safely_rollback() ||
+         was_insert_delayed)
+     {
++#ifdef WITH_WSREP
++      if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+       if (mysql_bin_log.is_open())
++#endif
+       {
+         int errcode= 0;
+       if (error <= 0)
+@@ -3773,7 +3777,13 @@ bool select_insert::send_eof()
+   DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
+                        trans_table, table->file->table_type()));
++#ifdef WITH_WSREP
++  error= (thd->wsrep_conflict_state == MUST_ABORT ||
++          thd->wsrep_conflict_state == CERT_FAILURE) ? -1 :
++    (bulk_insert_started ?
++#else
+   error= (bulk_insert_started ?
++#endif /* WITH_WSREP */
+           table->file->ha_end_bulk_insert() : 0);
+   if (!error && thd->is_error())
+     error= thd->get_stmt_da()->sql_errno();
+@@ -3800,8 +3810,13 @@ bool select_insert::send_eof()
+     events are in the transaction cache and will be written when
+     ha_autocommit_or_rollback() is issued below.
+   */
++#ifdef WITH_WSREP
++  if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) &&
++      (!error || thd->transaction.stmt.cannot_safely_rollback()))
++#else
+   if (mysql_bin_log.is_open() &&
+       (!error || thd->transaction.stmt.cannot_safely_rollback()))
++#endif
+   {
+     int errcode= 0;
+     if (!error)
+@@ -3886,7 +3901,11 @@ void select_insert::abort_result_set() {
+     transactional_table= table->file->has_transactions();
+     if (thd->transaction.stmt.cannot_safely_rollback())
+     {
++#ifdef WITH_WSREP
++        if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+         if (mysql_bin_log.is_open())
++#endif
+         {
+           int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+           /* error of writing binary log is ignored */
+@@ -4293,7 +4312,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
+                             /* show_database */ TRUE);
+   DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */
++#ifdef WITH_WSREP
++  if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+   if (mysql_bin_log.is_open())
++#endif /* WITH_WSREP */
+   {
+     int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+     result= thd->binlog_query(THD::STMT_QUERY_TYPE,
+@@ -4303,6 +4326,9 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
+                               /* suppress_use */ FALSE,
+                               errcode);
+   }
++#ifdef WITH_WSREP
++  ha_wsrep_fake_trx_id(thd);
++#endif
+   return result;
+ }
+@@ -4368,6 +4394,18 @@ bool select_create::send_eof()
+     {
+       trans_commit_stmt(thd);
+       trans_commit_implicit(thd);
++#ifdef WITH_WSREP
++      mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++      if (thd->wsrep_conflict_state != NO_CONFLICT)
++      {
++        WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s", 
++                    thd->thread_id, thd->wsrep_conflict_state, thd->query());
++        mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++        abort_result_set();
++      return TRUE;
++      }
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++#endif /* WITH_WSREP */
+     }
+     table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
+diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
+index 0ba8bcb..f9e1e6b 100644
+--- a/sql/sql_parse.cc
++++ b/sql/sql_parse.cc
+@@ -107,6 +107,12 @@ using std::min;
+ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#include "wsrep_thd.h"
++static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
++                              Parser_state *parser_state);
++#endif /* WITH_WSREP */
+ /**
+   @defgroup Runtime_Environment Runtime Environment
+   @{
+@@ -823,7 +829,11 @@ void do_handle_bootstrap(THD *thd)
+   if (my_thread_init() || thd->store_globals())
+   {
+ #ifndef EMBEDDED_LIBRARY
++#ifdef WITH_WSREP
++    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#else
+     close_connection(thd, ER_OUT_OF_RESOURCES);
++#endif /* WITH_WSREP */
+ #endif
+     thd->fatal_error();
+     goto end;
+@@ -913,7 +923,18 @@ bool do_command(THD *thd)
+   enum enum_server_command command;
+   DBUG_ENTER("do_command");
+-
++#ifdef WITH_WSREP
++  if (WSREP(thd))
++  {
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    thd->wsrep_query_state= QUERY_IDLE;
++    if (thd->wsrep_conflict_state==MUST_ABORT)
++    {
++      wsrep_client_rollback(thd);
++    }
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++#endif /* WITH_WSREP */
+   /*
+     indicator of uninitialized lex => normal flow of errors handling
+     (see my_message_sql)
+@@ -952,7 +973,6 @@ bool do_command(THD *thd)
+     matter here, because the read/recv() below doesn't use it.
+   */
+   DEBUG_SYNC(thd, "before_do_command_net_read");
+-
+   /*
+     Because of networking layer callbacks in place,
+     this call will maintain the following instrumentation:
+@@ -968,12 +988,45 @@ bool do_command(THD *thd)
+   packet_length= my_net_read(net);
+   thd->m_server_idle= false;
++#ifdef WITH_WSREP
++  if (WSREP(thd)) {
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    /* these THD's are aborted or are aborting during being idle */
++    if (thd->wsrep_conflict_state == ABORTING)
++    {
++      while (thd->wsrep_conflict_state == ABORTING) {
++        mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++        my_sleep(1000);
++        mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++      }
++      thd->store_globals();
++    }
++    else if (thd->wsrep_conflict_state == ABORTED)
++    {
++      thd->store_globals();
++    }
++
++    thd->wsrep_query_state= QUERY_EXEC;
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++#endif /* WITH_WSREP */
+   if (packet_length == packet_error)
+   {
+     DBUG_PRINT("info",("Got error %d reading command from socket %s",
+                      net->error,
+                      vio_description(net->vio)));
++#ifdef WITH_WSREP
++    if (WSREP(thd)) {
++      mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++      if (thd->wsrep_conflict_state == MUST_ABORT)
++      {
++        DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id));
++        wsrep_client_rollback(thd);
++      }
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    }
++#endif /* WITH_WSREP */
+     /* Instrument this broken statement as "statement/com/error" */
+     thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
+                                                  com_statement_info[COM_END].m_key);
+@@ -1026,6 +1079,33 @@ bool do_command(THD *thd)
+                      vio_description(net->vio), command,
+                      command_name[command].str));
++#ifdef WITH_WSREP
++  if (WSREP(thd)) {
++    /*
++     * bail out if DB snapshot has not been installed. We however,
++     * allow queries "SET" and "SHOW", they are trapped later in execute_command
++     */
++    if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
++        command != COM_QUERY        &&
++        command != COM_PING         &&
++        command != COM_QUIT         &&
++        command != COM_PROCESS_INFO &&
++        command != COM_PROCESS_KILL &&
++        command != COM_SET_OPTION   &&
++        command != COM_SHUTDOWN     &&
++        command != COM_SLEEP        &&
++        command != COM_STATISTICS   &&
++        command != COM_TIME         &&
++        command != COM_END
++    ) {
++      my_error(ER_UNKNOWN_COM_ERROR, MYF(0),
++             "WSREP has not yet prepared node for application use");
++      thd->protocol->end_statement();
++      return_value= FALSE;
++      goto out;
++    }
++  }
++#endif /* WITH_WSREP */
+   /* Restore read timeout value */
+   my_net_set_read_timeout(net, thd->variables.net_read_timeout);
+@@ -1033,6 +1113,22 @@ bool do_command(THD *thd)
+   return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
++#ifdef WITH_WSREP
++  if (WSREP(thd)) {
++    while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
++    {
++      return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
++                                   thd->wsrep_retry_query_len);
++    }
++  }
++  if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING)
++  {
++    my_free(thd->wsrep_retry_query);
++    thd->wsrep_retry_query      = NULL;
++    thd->wsrep_retry_query_len  = 0;
++    thd->wsrep_retry_command    = COM_CONNECT;
++  }
++#endif /* WITH_WSREP */
+ out:
+   /* The statement instrumentation must be closed in all cases. */
+   DBUG_ASSERT(thd->m_statement_psi == NULL);
+@@ -1108,6 +1204,36 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
+   DBUG_RETURN(FALSE);
+ }
++#ifdef WITH_WSREP
++static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables)
++{
++  int opt_readonly_saved = opt_readonly;
++  ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL);
++
++  opt_readonly = 0;
++  thd->security_ctx->master_access &= ~SUPER_ACL;
++
++  my_bool ret = !deny_updates_if_read_only_option(thd, all_tables);
++
++  opt_readonly = opt_readonly_saved;
++  thd->security_ctx->master_access |= flag_saved;
++
++  return ret;
++}
++
++static void wsrep_copy_query(THD *thd)
++{
++  thd->wsrep_retry_command   = thd->get_command();
++  thd->wsrep_retry_query_len = thd->query_length();
++  if (thd->wsrep_retry_query) {
++      my_free(thd->wsrep_retry_query);
++  }
++  thd->wsrep_retry_query     = (char *)my_malloc(
++                                 thd->wsrep_retry_query_len + 1, MYF(0));
++  strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len);
++  thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0';
++}
++#endif /* WITH_WSREP */
+ /**
+   Perform one connection-level (COM_XXXX) command.
+@@ -1136,7 +1262,42 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
+   bool error= 0;
+   DBUG_ENTER("dispatch_command");
+   DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
++#ifdef WITH_WSREP
++  if (WSREP(thd)) {
++    if (!thd->in_multi_stmt_transaction_mode())
++    {
++      thd->wsrep_PA_safe= true;
++    }
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    thd->wsrep_query_state= QUERY_EXEC;
++    if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
++    {
++      thd->wsrep_conflict_state= NO_CONFLICT;
++    }
++    if (thd->wsrep_conflict_state== MUST_ABORT)
++    {
++      wsrep_client_rollback(thd);
++    }
++    if (thd->wsrep_conflict_state== ABORTED)
++    {
++      my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
++      WSREP_DEBUG("Deadlock error for: %s", thd->query());
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++      thd->killed               = THD::NOT_KILLED;
++      thd->mysys_var->abort     = 0;
++      thd->wsrep_conflict_state = NO_CONFLICT;
++      thd->wsrep_retry_counter  = 0;
++      /*
++        Increment threads running to compensate dec_thread_running() called
++        after dispatch_end label.
++      */
++      inc_thread_running();
++      goto dispatch_end;
++    }
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++#endif /* WITH_WSREP */
+   /* SHOW PROFILE instrumentation, begin */
+ #if defined(ENABLED_PROFILING)
+   thd->profiling.start_new_query();
+@@ -1319,6 +1480,37 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
+     DBUG_PRINT("query",("%-.4096s",thd->query()));
++#ifdef WITH_WSREP
++
++  if (WSREP(thd)) {
++    if (!thd->in_multi_stmt_transaction_mode())
++    {
++      thd->wsrep_PA_safe= true;
++    }
++
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    thd->wsrep_query_state= QUERY_EXEC;
++    if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
++    {
++      thd->wsrep_conflict_state= NO_CONFLICT;
++    }
++
++    if (thd->wsrep_conflict_state== MUST_ABORT)
++    {
++      wsrep_client_rollback(thd);
++    }
++    if (thd->wsrep_conflict_state== ABORTED) 
++    {
++      my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
++      WSREP_DEBUG("Deadlock error for: %s", thd->query());
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++      thd->killed= THD::NOT_KILLED;
++      thd->mysys_var->abort= 0;
++      goto dispatch_end;
++    }
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++#endif /* WITH_WSREP */
+ #if defined(ENABLED_PROFILING)
+     thd->profiling.set_query_source(thd->query(), thd->query_length());
+ #endif
+@@ -1329,7 +1521,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
+     if (parser_state.init(thd, thd->query(), thd->query_length()))
+       break;
++#ifdef WITH_WSREP
++    wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
++#else
+     mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
++#endif /* WITH_WSREP */
+     while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) &&
+            ! thd->is_error())
+@@ -1401,10 +1597,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
+         Count each statement from the client.
+       */
+       statistic_increment(thd->status_var.questions, &LOCK_status);
++#ifdef WITH_WSREP
++      if (!WSREP(thd))
++      thd->set_time(); /* Reset the query start time. */
++#else
+       thd->set_time(); /* Reset the query start time. */
++#endif /* WITH_WSREP */
+       parser_state.reset(beginning_of_next_stmt, length);
+       /* TODO: set thd->lex->sql_command to SQLCOM_END here */
++#ifdef WITH_WSREP
++      wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
++#else
+       mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
++#endif /* WITH_WSREP */
+     }
+     DBUG_PRINT("info",("query ready"));
+@@ -1746,6 +1951,26 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
+     my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+     break;
+   }
++#ifdef WITH_WSREP
++ dispatch_end:
++
++  if (WSREP(thd)) {
++    /* wsrep BF abort in query exec phase */
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    if ((thd->wsrep_conflict_state != REPLAYING) &&
++        (thd->wsrep_conflict_state != RETRY_AUTOCOMMIT)) {
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++      thd->update_server_status();
++      thd->protocol->end_statement();
++      query_cache_end_of_result(thd);
++    } 
++    else
++    {
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    }
++  } else { /* if (WSREP(thd))... */
++#endif /* WITH_WSREP */
+ done:
+   DBUG_ASSERT(thd->derived_tables == NULL &&
+@@ -1758,6 +1983,9 @@ done:
+     thd->send_kill_message();
+   thd->protocol->end_statement();
+   query_cache_end_of_result(thd);
++#ifdef WITH_WSREP
++  }
++#endif /* WITH_WSREP */
+   if (!thd->is_error() && !thd->killed_errno())
+     mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0);
+@@ -2256,6 +2484,13 @@ err:
+   return TRUE;
+ }
++#ifdef WITH_WSREP
++static bool wsrep_is_show_query(enum enum_sql_command command)
++{
++  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
++  return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0;
++}
++#endif /* WITH_WSREP */
+ /**
+   Execute command saved in thd and lex->sql_command.
+@@ -2497,7 +2732,6 @@ mysql_execute_command(THD *thd)
+ #ifdef HAVE_REPLICATION
+   } /* endif unlikely slave */
+ #endif
+-
+   status_var_increment(thd->status_var.com_stat[lex->sql_command]);
+   Opt_trace_start ots(thd, all_tables, lex->sql_command, &lex->var_list,
+@@ -2506,6 +2740,45 @@ mysql_execute_command(THD *thd)
+   Opt_trace_object trace_command(&thd->opt_trace);
+   Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
++#ifdef WITH_WSREP
++  if (WSREP(thd)) {
++    /*
++      change LOCK TABLE WRITE to transaction
++    */
++    if (lex->sql_command== SQLCOM_LOCK_TABLES && wsrep_convert_LOCK_to_trx)
++    {
++      for (TABLE_LIST *table= all_tables; table; table= table->next_global)
++      {
++        if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
++        {
++          lex->sql_command= SQLCOM_BEGIN;
++          thd->wsrep_converted_lock_session= true;
++          break;
++        }
++      }
++    }
++    if (lex->sql_command== SQLCOM_UNLOCK_TABLES &&
++        thd->wsrep_converted_lock_session)
++    {
++      thd->wsrep_converted_lock_session= false;
++      lex->sql_command= SQLCOM_COMMIT;
++      lex->tx_release= TVL_NO;
++    }
++
++    /*
++     * bail out if DB snapshot has not been installed. We however,
++     * allow SET and SHOW queries
++     */
++    if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
++        lex->sql_command != SQLCOM_SET_OPTION &&
++        !wsrep_is_show_query(lex->sql_command))
++    {
++      my_error(ER_UNKNOWN_COM_ERROR, MYF(0),
++               "WSREP has not yet prepared node for application use");
++      goto error;
++    }
++  }
++#endif /* WITH_WSREP */
+   DBUG_ASSERT(thd->transaction.stmt.cannot_safely_rollback() == FALSE);
+@@ -2546,7 +2819,13 @@ mysql_execute_command(THD *thd)
+     /* Commit the normal transaction if one is active. */
+     if (trans_commit_implicit(thd))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     /* Release metadata locks acquired in this transaction. */
+     thd->mdl_context.release_transactional_locks();
+   }
+@@ -2600,7 +2879,9 @@ mysql_execute_command(THD *thd)
+   {
+     system_status_var old_status_var= thd->status_var;
+     thd->initial_status_var= &old_status_var;
+-
++#ifdef WITH_WSREP
++    if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
++#endif /* WITH_WSREP */
+     if (!(res= select_precheck(thd, lex, all_tables, first_table)))
+       res= execute_sqlcom_select(thd, all_tables);
+@@ -2616,6 +2897,9 @@ mysql_execute_command(THD *thd)
+                        &old_status_var);
+     thd->status_var= old_status_var;
+     mysql_mutex_unlock(&LOCK_status);
++#ifdef WITH_WSREP
++    if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd);
++#endif /* WITH_WSREP */
+     break;
+   }
+   case SQLCOM_SHOW_EVENTS:
+@@ -2633,12 +2917,22 @@ mysql_execute_command(THD *thd)
+   case SQLCOM_SHOW_PLUGINS:
+   case SQLCOM_SHOW_FIELDS:
+   case SQLCOM_SHOW_KEYS:
++#ifndef WITH_WSREP
+   case SQLCOM_SHOW_VARIABLES:
+   case SQLCOM_SHOW_CHARSETS:
+   case SQLCOM_SHOW_COLLATIONS:
+   case SQLCOM_SHOW_STORAGE_ENGINES:
+   case SQLCOM_SHOW_PROFILE:
++#endif /* WITH_WSREP */
+   case SQLCOM_SELECT:
++#ifdef WITH_WSREP
++    if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
++  case SQLCOM_SHOW_VARIABLES:
++  case SQLCOM_SHOW_CHARSETS:
++  case SQLCOM_SHOW_COLLATIONS:
++  case SQLCOM_SHOW_STORAGE_ENGINES:
++  case SQLCOM_SHOW_PROFILE:
++#endif /* WITH_WSREP */
+   {
+     thd->status_var.last_query_cost= 0.0;
+     thd->status_var.last_query_partial_plans= 0;
+@@ -2938,7 +3232,7 @@ case SQLCOM_PREPARE:
+        */
+       if (thd->query_name_consts && 
+           mysql_bin_log.is_open() &&
+-          thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
++          WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT &&
+           !mysql_bin_log.is_query_in_union(thd, thd->query_id))
+       {
+         List_iterator_fast<Item> it(select_lex->item_list);
+@@ -3056,6 +3350,15 @@ case SQLCOM_PREPARE:
+       }
+       else
+       {
++#ifdef WITH_WSREP
++        /* in STATEMENT format, we probably have to replicate also temporary
++           tables, like mysql replication does
++        */
++      if (!thd->is_current_stmt_binlog_format_row() ||
++          !(create_info.options & HA_LEX_CREATE_TMP_TABLE))
++       WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name,
++                                 NULL)
++#endif /* WITH_WSREP */
+         /* Regular CREATE TABLE */
+         res= mysql_create_table(thd, create_table,
+                                 &create_info, &alter_info);
+@@ -3089,6 +3392,7 @@ end_with_restore_list:
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+     if (check_one_table_access(thd, INDEX_ACL, all_tables))
+       goto error; /* purecov: inspected */
++    WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
+     /*
+       Currently CREATE INDEX or DROP INDEX cause a full table rebuild
+       and thus classify as slow administrative statements just like
+@@ -3181,8 +3485,11 @@ end_with_restore_list:
+         goto error;
+     }
++    WSREP_TO_ISOLATION_BEGIN(0, 0, first_table)
+     if (mysql_rename_tables(thd, first_table, 0))
++    {
+       goto error;
++    }
+     break;
+   }
+ #ifndef EMBEDDED_LIBRARY
+@@ -3208,6 +3515,10 @@ end_with_restore_list:
+     goto error;
+ #else
+     {
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
++#endif /* WITH_WSREP */
++
+      /*
+         Access check:
+         SHOW CREATE TABLE require any privileges on the table level (ie
+@@ -3270,6 +3581,10 @@ end_with_restore_list:
+   case SQLCOM_CHECKSUM:
+   {
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
++#ifdef WITH_WSREP
++    if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
++#endif /* WITH_WSREP */
++
+     if (check_table_access(thd, SELECT_ACL, all_tables,
+                            FALSE, UINT_MAX, FALSE))
+       goto error; /* purecov: inspected */
+@@ -3278,6 +3593,10 @@ end_with_restore_list:
+     break;
+   }
+   case SQLCOM_UPDATE:
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) &&
++          wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
++#endif /* WITH_WSREP */      
+   {
+     ha_rows found= 0, updated= 0;
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+@@ -3317,6 +3636,10 @@ end_with_restore_list:
+     /* if we switched from normal update, rights are checked */
+     if (up_result != 2)
+     {
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) &&
++          wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
++#endif /* WITH_WSREP */
+       if ((res= multi_update_precheck(thd, all_tables)))
+         break;
+     }
+@@ -3386,6 +3709,10 @@ end_with_restore_list:
+     break;
+   }
+   case SQLCOM_REPLACE:
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) &&
++          wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
++#endif /* WITH_WSREP */
+ #ifndef DBUG_OFF
+     if (mysql_bin_log.is_open())
+     {
+@@ -3420,6 +3747,10 @@ end_with_restore_list:
+     }
+ #endif
+   case SQLCOM_INSERT:
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) &&
++          wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
++#endif /* WITH_WSREP */      
+   {
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+@@ -3465,11 +3796,23 @@ end_with_restore_list:
+   }
+   case SQLCOM_REPLACE_SELECT:
+   case SQLCOM_INSERT_SELECT:
++#ifdef WITH_WSREP
++      if (WSREP_CLIENT(thd) &&
++          wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
++#endif /* WITH_WSREP */      
+   {
+     select_insert *sel_result;
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+     if ((res= insert_precheck(thd, all_tables)))
+       break;
++#ifdef WITH_WSREP
++    if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED)
++    {
++      thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING;
++      WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL);
++    }
++
++#endif
+     /*
+       INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/
+       INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY
+@@ -3555,6 +3898,10 @@ end_with_restore_list:
+     break;
+   }
+   case SQLCOM_DELETE:
++#ifdef WITH_WSREP
++    if (WSREP_CLIENT(thd) && 
++        wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
++#endif /* WITH_WSREP */
+   {
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+     if ((res= delete_precheck(thd, all_tables)))
+@@ -3570,6 +3917,10 @@ end_with_restore_list:
+     break;
+   }
+   case SQLCOM_DELETE_MULTI:
++#ifdef WITH_WSREP
++    if (WSREP_CLIENT(thd) && 
++        wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
++#endif /* WITH_WSREP */
+   {
+     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+     TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
+@@ -3636,6 +3987,18 @@ end_with_restore_list:
+       if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
+       goto error;                             /* purecov: inspected */
+     }
++#ifdef WITH_WSREP
++   for (TABLE_LIST *table= all_tables; table; table= table->next_global)
++   {
++     if (!lex->drop_temporary                       &&
++       (!thd->is_current_stmt_binlog_format_row() ||
++        !find_temporary_table(thd, table)))
++     {
++       WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
++       break;
++     }
++   }
++#endif /* WITH_WSREP */
+     /* DDL and binlog write order are protected by metadata locks. */
+     res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
+                       lex->drop_temporary);
+@@ -3673,7 +4036,6 @@ end_with_restore_list:
+     if (!mysql_change_db(thd, &db_str, FALSE))
+       my_ok(thd);
+-
+     break;
+   }
+@@ -3836,6 +4198,7 @@ end_with_restore_list:
+ #endif
+     if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
+       break;
++    WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
+     res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
+                               lex->name.str), &create_info, 0);
+     break;
+@@ -3860,6 +4223,7 @@ end_with_restore_list:
+ #endif
+     if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
+       break;
++    WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
+     res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
+     break;
+   }
+@@ -3883,6 +4247,7 @@ end_with_restore_list:
+       res= 1;
+       break;
+     }
++    WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL)
+     res= mysql_upgrade_db(thd, db);
+     if (!res)
+       my_ok(thd);
+@@ -3910,6 +4275,7 @@ end_with_restore_list:
+ #endif
+     if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0))
+       break;
++    WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL)
+     res= mysql_alter_db(thd, db->str, &create_info);
+     break;
+   }
+@@ -3939,6 +4305,7 @@ end_with_restore_list:
+     if (res)
+       break;
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     switch (lex->sql_command) {
+     case SQLCOM_CREATE_EVENT:
+     {
+@@ -3973,6 +4340,7 @@ end_with_restore_list:
+                                    lex->spname->m_name);
+     break;
+   case SQLCOM_DROP_EVENT:
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (!(res= Events::drop_event(thd,
+                                   lex->spname->m_db, lex->spname->m_name,
+                                   lex->drop_if_exists)))
+@@ -3987,6 +4355,7 @@ end_with_restore_list:
+     if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 0))
+       break;
+ #ifdef HAVE_DLOPEN
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (!(res = mysql_create_function(thd, &lex->udf)))
+       my_ok(thd);
+ #else
+@@ -4001,6 +4370,7 @@ end_with_restore_list:
+     if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) &&
+         check_global_access(thd,CREATE_USER_ACL))
+       break;
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     /* Conditionally writes to binlog */
+     if (!(res= mysql_create_user(thd, lex->users_list)))
+       my_ok(thd);
+@@ -4012,6 +4382,7 @@ end_with_restore_list:
+         check_global_access(thd,CREATE_USER_ACL))
+       break;
+     /* Conditionally writes to binlog */
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (!(res= mysql_drop_user(thd, lex->users_list)))
+       my_ok(thd);
+     break;
+@@ -4022,6 +4393,7 @@ end_with_restore_list:
+         check_global_access(thd,CREATE_USER_ACL))
+       break;
+     /* Conditionally writes to binlog */
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (!(res= mysql_rename_user(thd, lex->users_list)))
+       my_ok(thd);
+     break;
+@@ -4036,6 +4408,7 @@ end_with_restore_list:
+     thd->binlog_invoker();
+     /* Conditionally writes to binlog */
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (!(res = mysql_revoke_all(thd, lex->users_list)))
+       my_ok(thd);
+     break;
+@@ -4102,6 +4475,7 @@ end_with_restore_list:
+                                 lex->type == TYPE_ENUM_PROCEDURE, 0))
+         goto error;
+         /* Conditionally writes to binlog */
++        WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+         res= mysql_routine_grant(thd, all_tables,
+                                  lex->type == TYPE_ENUM_PROCEDURE, 
+                                  lex->users_list, grants,
+@@ -4115,6 +4489,7 @@ end_with_restore_list:
+                         all_tables, FALSE, UINT_MAX, FALSE))
+         goto error;
+         /* Conditionally writes to binlog */
++        WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+         res= mysql_table_grant(thd, all_tables, lex->users_list,
+                              lex->columns, lex->grant,
+                              lex->sql_command == SQLCOM_REVOKE);
+@@ -4130,6 +4505,7 @@ end_with_restore_list:
+       }
+       else
+       {
++          WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+         /* Conditionally writes to binlog */
+         res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
+                           lex->sql_command == SQLCOM_REVOKE,
+@@ -4258,7 +4634,13 @@ end_with_restore_list:
+ #endif
+   case SQLCOM_BEGIN:
+     if (trans_begin(thd, lex->start_transaction_opt))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     my_ok(thd);
+     break;
+   case SQLCOM_COMMIT:
+@@ -4272,7 +4654,13 @@ end_with_restore_list:
+                       (thd->variables.completion_type == 2 &&
+                        lex->tx_release != TVL_NO));
+     if (trans_commit(thd))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     thd->mdl_context.release_transactional_locks();
+     /* Begin transaction with the same isolation level. */
+     if (tx_chain)
+@@ -4289,7 +4677,20 @@ end_with_restore_list:
+     /* Disconnect the current client connection. */
+     if (tx_release)
+       thd->killed= THD::KILL_CONNECTION;
++#ifdef WITH_WSREP
++    if (WSREP(thd)) {
++
++      if (thd->wsrep_conflict_state == NO_CONFLICT ||
++          thd->wsrep_conflict_state == REPLAYING)
++      {
++        my_ok(thd);
++      }
++    } else {
++#endif /* WITH_WSREP */
+     my_ok(thd);
++#ifdef WITH_WSREP
++    }
++#endif /* WITH_WSREP */
+     break;
+   }
+   case SQLCOM_ROLLBACK:
+@@ -4303,7 +4704,13 @@ end_with_restore_list:
+                       (thd->variables.completion_type == 2 &&
+                        lex->tx_release != TVL_NO));
+     if (trans_rollback(thd))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     thd->mdl_context.release_transactional_locks();
+     /* Begin transaction with the same isolation level. */
+     if (tx_chain)
+@@ -4320,7 +4727,17 @@ end_with_restore_list:
+     /* Disconnect the current client connection. */
+     if (tx_release)
+       thd->killed= THD::KILL_CONNECTION;
++#ifdef WITH_WSREP
++    if (WSREP(thd)) {
++      if (thd->wsrep_conflict_state == NO_CONFLICT) {
++        my_ok(thd);
++      }
++    } else {
++#endif /* WITH_WSREP */
+     my_ok(thd);
++#ifdef WITH_WSREP
++    }
++#endif /* WITH_WSREP */
+     break;
+   }
+   case SQLCOM_RELEASE_SAVEPOINT:
+@@ -4386,6 +4803,7 @@ end_with_restore_list:
+     if (sp_process_definer(thd))
+       goto create_sp_error;
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     res= (sp_result= sp_create_routine(thd, lex->sphead));
+     switch (sp_result) {
+     case SP_OK: {
+@@ -4602,6 +5020,7 @@ create_sp_error:
+         already puts on CREATE FUNCTION.
+       */
+       /* Conditionally writes to binlog */
++      WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+       int sp_result= sp_update_routine(thd, sp_type, lex->spname,
+                                        &lex->sp_chistics);
+       if (thd->killed)
+@@ -4673,6 +5092,7 @@ create_sp_error:
+                                lex->sql_command == SQLCOM_DROP_PROCEDURE,
+                                false))
+         goto error;
++      WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+       enum_sp_type sp_type= (lex->sql_command == SQLCOM_DROP_PROCEDURE) ?
+                             SP_TYPE_PROCEDURE : SP_TYPE_FUNCTION;
+@@ -4793,6 +5213,7 @@ create_sp_error:
+         Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
+         as specified through the thd->lex->create_view_mode flag.
+       */
++      WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+       res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
+       break;
+     }
+@@ -4801,12 +5222,14 @@ create_sp_error:
+       if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
+         goto error;
+       /* Conditionally writes to binlog. */
++      WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+       res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
+       break;
+     }
+   case SQLCOM_CREATE_TRIGGER:
+   {
+     /* Conditionally writes to binlog. */
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     res= mysql_create_or_drop_trigger(thd, all_tables, 1);
+     break;
+@@ -4814,6 +5237,7 @@ create_sp_error:
+   case SQLCOM_DROP_TRIGGER:
+   {
+     /* Conditionally writes to binlog. */
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     res= mysql_create_or_drop_trigger(thd, all_tables, 0);
+     break;
+   }
+@@ -4834,7 +5258,13 @@ create_sp_error:
+     break;
+   case SQLCOM_XA_COMMIT:
+     if (trans_xa_commit(thd))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     thd->mdl_context.release_transactional_locks();
+     /*
+       We've just done a commit, reset transaction
+@@ -4846,7 +5276,13 @@ create_sp_error:
+     break;
+   case SQLCOM_XA_ROLLBACK:
+     if (trans_xa_rollback(thd))
++    {
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       goto error;
++    }
+     thd->mdl_context.release_transactional_locks();
+     /*
+       We've just done a rollback, reset transaction
+@@ -4866,11 +5302,13 @@ create_sp_error:
+       my_ok(thd);
+     break;
+   case SQLCOM_INSTALL_PLUGIN:
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
+                                      &thd->lex->ident)))
+       my_ok(thd);
+     break;
+   case SQLCOM_UNINSTALL_PLUGIN:
++    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+     if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
+       my_ok(thd);
+     break;
+@@ -5012,6 +5450,9 @@ finish:
+   /* Free tables */
+   THD_STAGE_INFO(thd, stage_closing_tables);
+   close_thread_tables(thd);
++#ifdef WITH_WSREP
++  thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
++#endif /* WITH_WSREP */
+ #ifndef DBUG_OFF
+   if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt)
+@@ -5057,6 +5498,22 @@ finish:
+   {
+     thd->mdl_context.release_statement_locks();
+   }
++  WSREP_TO_ISOLATION_END;
++
++#ifdef WITH_WSREP
++  /*
++    Force release of transactional locks if not in active MST and wsrep is on.
++  */
++  if (WSREP(thd) &&
++      ! thd->in_sub_stmt &&
++      ! thd->in_active_multi_stmt_transaction() &&
++      thd->mdl_context.has_transactional_locks())
++  {
++    WSREP_DEBUG("Forcing release of transactional locks for thd %lu",
++               thd->thread_id);
++    thd->mdl_context.release_transactional_locks();
++  }
++#endif /* WITH_WSREP */
+   DBUG_RETURN(res || thd->is_error());
+ }
+@@ -5986,6 +6443,26 @@ void THD::reset_for_next_command()
+   thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
+   thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
++#ifdef WITH_WSREP
++  /*
++    Autoinc variables should be adjusted only for locally executed
++    transactions. Appliers and replayers are either processing ROW
++    events or get autoinc variable values from Query_log_event.
++  */
++  if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) {
++    if (wsrep_auto_increment_control)
++    {
++      if (thd->variables.auto_increment_offset !=
++        global_system_variables.auto_increment_offset)
++      thd->variables.auto_increment_offset=
++        global_system_variables.auto_increment_offset;
++      if (thd->variables.auto_increment_increment !=
++        global_system_variables.auto_increment_increment)
++      thd->variables.auto_increment_increment=
++        global_system_variables.auto_increment_increment;
++    }
++  }
++#endif /* WITH_WSREP */
+   thd->query_start_used= thd->query_start_usec_used= 0;
+   thd->is_fatal_error= thd->time_zone_used= 0;
+   /*
+@@ -6211,6 +6688,132 @@ void mysql_init_multi_delete(LEX *lex)
+   lex->query_tables_last= &lex->query_tables;
+ }
++#ifdef WITH_WSREP
++static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
++                              Parser_state *parser_state)
++{
++  bool is_autocommit=
++    !thd->in_multi_stmt_transaction_mode()                  &&
++    thd->wsrep_conflict_state == NO_CONFLICT                &&
++    !thd->wsrep_applier                                     &&
++    wsrep_read_only_option(thd, thd->lex->query_tables);
++
++  do
++  {
++    if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
++    {
++      thd->wsrep_conflict_state= NO_CONFLICT;
++    }
++    mysql_parse(thd, rawbuf, length, parser_state);
++
++    if (WSREP(thd)) {
++      /* wsrep BF abort in query exec phase */
++      mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++      if (thd->wsrep_conflict_state == MUST_ABORT) {
++        wsrep_client_rollback(thd);
++
++        WSREP_DEBUG("abort in exec query state, avoiding autocommit");
++      }
++
++      /* checking if BF trx must be replayed */
++      if (thd->wsrep_conflict_state== MUST_REPLAY)
++      {
++        wsrep_replay_transaction(thd);
++      }
++
++      /* setting error code for BF aborted trxs */
++      if (thd->wsrep_conflict_state == ABORTED ||
++          thd->wsrep_conflict_state == CERT_FAILURE)
++      {
++        mysql_reset_thd_for_next_command(thd);
++        thd->killed= THD::NOT_KILLED;
++        if (is_autocommit                           &&
++            thd->lex->sql_command != SQLCOM_SELECT  &&
++           (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
++        {
++          WSREP_DEBUG("wsrep retrying AC query: %s",
++                      (thd->query()) ? thd->query() : "void");
++
++          close_thread_tables(thd);
++
++          thd->wsrep_conflict_state= RETRY_AUTOCOMMIT;
++          thd->wsrep_retry_counter++;            // grow
++          wsrep_copy_query(thd);
++          thd->set_time();
++          parser_state->reset(rawbuf, length);
++
++          /* PSI end */
++          MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
++          thd->m_statement_psi= NULL;
++
++          /* DTRACE end */
++          if (MYSQL_QUERY_DONE_ENABLED())
++          {
++            MYSQL_QUERY_DONE(thd->is_error());
++          }
++
++          /* SHOW PROFILE end */
++#if defined(ENABLED_PROFILING)
++          thd->profiling.finish_current_query();
++#endif
++
++          /* SHOW PROFILE begin */
++#if defined(ENABLED_PROFILING)
++          thd->profiling.start_new_query("continuing");
++          thd->profiling.set_query_source(rawbuf, length);
++#endif
++
++          /* DTRACE begin */
++          MYSQL_QUERY_START(rawbuf, thd->thread_id,
++                            (char *) (thd->db ? thd->db : ""),
++                            &thd->security_ctx->priv_user[0],
++                            (char *) thd->security_ctx->host_or_ip);
++
++          /* PSI begin */
++          thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
++                                                      com_statement_info[thd->get_command()].m_key,
++                                                      thd->db, thd->db_length,
++                                                      thd->charset());
++        }
++        else
++        {
++          WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s",
++                      (thd->wsrep_conflict_state == ABORTED) ?
++                      "BF Aborted" : "cert failure",
++                      thd->thread_id, is_autocommit, thd->wsrep_retry_counter,
++                      thd->variables.wsrep_retry_autocommit, thd->query());
++          my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
++          thd->killed= THD::NOT_KILLED;
++          thd->wsrep_conflict_state= NO_CONFLICT;
++          if (thd->wsrep_conflict_state != REPLAYING)
++            thd->wsrep_retry_counter= 0;             //  reset
++        }
++      }
++      else
++      {
++        set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
++      }
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    }
++  }  while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT);
++
++  if (thd->wsrep_retry_query)
++  {
++    WSREP_DEBUG("releasing retry_query: "
++                "conf %d sent %d kill %d  errno %d SQL %s",
++                thd->wsrep_conflict_state,
++                thd->get_stmt_da()->is_sent(),
++                thd->killed,
++                thd->get_stmt_da()->is_error() ? 
++              thd->get_stmt_da()->sql_errno() : 0,
++                thd->wsrep_retry_query);
++    my_free(thd->wsrep_retry_query);
++    thd->wsrep_retry_query      = NULL;
++    thd->wsrep_retry_query_len  = 0;
++    thd->wsrep_retry_command    = COM_CONNECT;
++  }
++}
++#endif /* WITH_WSREP */
+ /*
+   When you modify mysql_parse(), you may need to mofify
+@@ -7265,8 +7868,14 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
+       slayage if both are string-equal.
+     */
++#ifdef WITH_WSREP
++    if (((thd->security_ctx->master_access & SUPER_ACL) ||
++        thd->security_ctx->user_matches(tmp->security_ctx)) &&
++        !wsrep_thd_is_BF((void *)tmp, true))
++#else
+     if ((thd->security_ctx->master_access & SUPER_ACL) ||
+         thd->security_ctx->user_matches(tmp->security_ctx))
++#endif /* WITH_WSREP */
+     {
+       /* process the kill only if thread is not already undergoing any kill
+          connection.
+diff --git a/sql/sql_parse.h b/sql/sql_parse.h
+index b1124d1..c54bc96 100644
+--- a/sql/sql_parse.h
++++ b/sql/sql_parse.h
+@@ -210,6 +210,22 @@ inline bool is_supported_parser_charset(const CHARSET_INFO *cs)
+ {
+   return (cs->mbminlen == 1);
+ }
++#ifdef WITH_WSREP
++
++#define WSREP_MYSQL_DB (char *)"mysql"
++#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_)                   \
++  if (WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) goto error;
++
++#define WSREP_TO_ISOLATION_END                                              \
++  if (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER))             \
++    wsrep_to_isolation_end(thd);
++
++#else
++
++#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_)
++#define WSREP_TO_ISOLATION_END 
++
++#endif /* WITH_WSREP */
+ extern "C" bool sqlcom_can_generate_row_events(const THD *thd);
+diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
+index 15ead35..dbf2be0 100644
+--- a/sql/sql_partition_admin.cc
++++ b/sql/sql_partition_admin.cc
+@@ -767,6 +767,19 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
+   if (check_one_table_access(thd, DROP_ACL, first_table))
+     DBUG_RETURN(TRUE);
++#ifdef WITH_WSREP
++  TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
++
++  if ((!thd->is_current_stmt_binlog_format_row() ||
++       !find_temporary_table(thd, first_table))  &&
++      wsrep_to_isolation_begin(
++        thd, first_table->db, first_table->table_name, NULL)
++      )
++  {
++    WSREP_WARN("ALTER TABLE isolation failure");
++    DBUG_RETURN(TRUE);
++  }
++#endif /* WITH_WSREP */
+   if (open_tables(thd, &first_table, &table_counter, 0))
+     DBUG_RETURN(true);
+diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
+index bc89a8c..e43b2f2 100644
+--- a/sql/sql_plugin.cc
++++ b/sql/sql_plugin.cc
+@@ -2827,7 +2827,11 @@ void plugin_thdvar_init(THD *thd, bool enable_plugins)
+   thd->variables.dynamic_variables_size= 0;
+   thd->variables.dynamic_variables_ptr= 0;
++#ifdef WITH_WSREP
++  if ((!WSREP(thd) || !thd->wsrep_applier) && enable_plugins)
++#else
+   if (enable_plugins)
++#endif
+   {
+     mysql_mutex_lock(&LOCK_plugin);
+     thd->variables.table_plugin=
+diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
+index d187418..5576e69 100644
+--- a/sql/sql_prepare.cc
++++ b/sql/sql_prepare.cc
+@@ -3584,7 +3584,9 @@ Prepared_statement::set_parameters(String *expanded_query,
+   return res;
+ }
+-
++#ifdef WITH_WSREP
++void wsrep_replay_transaction(THD *thd);
++#endif /* WITH_WSREP */
+ /**
+   Execute a prepared statement. Re-prepare it a limited number
+   of times if necessary.
+@@ -3661,6 +3663,22 @@ reexecute:
+   thd->push_reprepare_observer(stmt_reprepare_observer);
+   error= execute(expanded_query, open_cursor) || thd->is_error();
++#ifdef WITH_WSREP
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  switch (thd->wsrep_conflict_state)
++  {
++  case CERT_FAILURE:
++    WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %ld err: %d",
++                thd->thread_id, thd->get_stmt_da()->sql_errno() );
++    thd->wsrep_conflict_state = NO_CONFLICT;
++    break;
++
++  case MUST_REPLAY:
++    (void)wsrep_replay_transaction(thd);
++  default: break;
++  }
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++#endif /* WITH_WSREP */
+   thd->pop_reprepare_observer();
+diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
+index 574ed4c..60ab476 100644
+--- a/sql/sql_reload.cc
++++ b/sql/sql_reload.cc
+@@ -249,7 +249,18 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
+         thd->global_read_lock.unlock_global_read_lock(thd);
+         return 1;
+       }
+-    }
++#ifdef WITH_WSREP
++      /*
++        We need to do it second time after wsrep appliers were blocked in
++        make_global_read_lock_block_commit(thd) above since they could have
++        modified the tables too.
++      */
++      if (WSREP(thd) && 
++        close_cached_tables(thd, tables, (options & REFRESH_FAST) ?
++                              FALSE : TRUE, TRUE))
++          result= 1;
++#endif /* WITH_WSREP */
++     }
+     else
+     {
+       if (thd && thd->locked_tables_mode)
+diff --git a/sql/sql_show.cc b/sql/sql_show.cc
+index 0dc4da5..9f73f8a 100644
+--- a/sql/sql_show.cc
++++ b/sql/sql_show.cc
+@@ -61,6 +61,9 @@
+ using std::max;
+ using std::min;
++#if !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
++#define MYSQL_MAX_VARIABLE_VALUE_LEN 1024
++#endif // !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
+ #define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
+ #ifdef WITH_PARTITION_STORAGE_ENGINE
+@@ -7938,7 +7941,8 @@ ST_FIELD_INFO variables_fields_info[]=
+ {
+   {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
+    SKIP_OPEN_TABLE},
+-  {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
++  {"VARIABLE_VALUE", MYSQL_MAX_VARIABLE_VALUE_LEN, MYSQL_TYPE_STRING, 0, 1,
++   "Value", SKIP_OPEN_TABLE},
+   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ };
+diff --git a/sql/sql_table.cc b/sql/sql_table.cc
+index d85585e..26b0e77 100644
+--- a/sql/sql_table.cc
++++ b/sql/sql_table.cc
+@@ -5301,6 +5301,60 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
+   uint not_used;
+   DBUG_ENTER("mysql_create_like_table");
++#ifdef WITH_WSREP
++  if (WSREP(thd) && !thd->wsrep_applier)
++  {
++    TABLE *tmp_table;
++    bool is_tmp_table= FALSE;
++
++    for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next)
++    {
++      if (!strcmp(src_table->db, tmp_table->s->db.str)     &&
++          !strcmp(src_table->table_name, tmp_table->s->table_name.str))
++      {
++        is_tmp_table= TRUE;
++        break;
++      }
++    }
++    if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
++    {
++      /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */
++      WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", 
++                  thd->query());
++    } 
++    else if (!is_tmp_table)
++    {
++      /* this is straight CREATE TABLE LIKE... eith no tmp tables */
++      WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
++    }
++    else
++    {
++      /* here we have CREATE TABLE LIKE <temporary table> 
++         the temporary table definition will be needed in slaves to
++         enable the create to succeed
++       */
++      TABLE_LIST tbl;
++      memset(&tbl, 0, sizeof(tbl));
++      tbl.db= src_table->db;
++      tbl.table_name= tbl.alias= src_table->table_name;
++      tbl.table= tmp_table;
++      char buf[2048];
++      String query(buf, sizeof(buf), system_charset_info);
++      query.length(0);  // Have to zero it since constructor doesn't
++
++      (void)  store_create_info(thd, &tbl, &query, NULL, TRUE);
++      WSREP_DEBUG("TMP TABLE: %s", query.ptr());
++
++      thd->wsrep_TOI_pre_query=     query.ptr();
++      thd->wsrep_TOI_pre_query_len= query.length();
++      
++      WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
++
++      thd->wsrep_TOI_pre_query=      NULL;
++      thd->wsrep_TOI_pre_query_len= 0;
++    }
++  }
++#endif
+   /*
+     We the open source table to get its description in HA_CREATE_INFO
+@@ -5474,6 +5528,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
+ err:
+   DBUG_RETURN(res);
++#ifdef WITH_WSREP
++ error:
++  thd->wsrep_TOI_pre_query= NULL;
++  DBUG_RETURN(TRUE);
++#endif /* WITH_WSREP */
+ }
+@@ -7883,6 +7942,17 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
+   DEBUG_SYNC(thd, "alter_opened_table");
++#ifdef WITH_WSREP
++  DBUG_EXECUTE_IF("sync.alter_opened_table",
++                  {
++                    const char act[]=
++                      "now "
++                      "wait_for signal.alter_opened_table";
++                    DBUG_ASSERT(!debug_sync_set_action(thd,
++                                                       STRING_WITH_LEN(act)));
++                  };);
++#endif // WITH_WSREP
++
+   if (error)
+     DBUG_RETURN(true);
+diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
+index e98b327..c9e92ad 100644
+--- a/sql/sql_trigger.cc
++++ b/sql/sql_trigger.cc
+@@ -434,8 +434,14 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
+     binlogged, so they share the same danger, so trust_function_creators
+     applies to them too.
+   */
++#ifdef WITH_WSREP
++  if (!trust_function_creators                                && 
++      (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())  &&
++      !(thd->security_ctx->master_access & SUPER_ACL))
++#else
+   if (!trust_function_creators && mysql_bin_log.is_open() &&
+       !(thd->security_ctx->master_access & SUPER_ACL))
++#endif /* WITH_WSREP */
+   {
+     my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0));
+     DBUG_RETURN(TRUE);
+@@ -2528,3 +2534,55 @@ bool load_table_name_for_trigger(THD *thd,
+   DBUG_RETURN(FALSE);
+ }
++#ifdef WITH_WSREP
++int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
++{
++  LEX *lex= thd->lex;
++  String stmt_query;
++
++  LEX_STRING definer_user;
++  LEX_STRING definer_host;
++
++  if (!lex->definer)
++  {
++    if (!thd->slave_thread)
++    {
++      if (!(lex->definer= create_default_definer(thd)))
++        return 1;
++    }
++  }
++
++  if (lex->definer)
++  {
++    /* SUID trigger. */
++
++    definer_user= lex->definer->user;
++    definer_host= lex->definer->host;
++  }
++  else
++  {
++    /* non-SUID trigger. */
++
++    definer_user.str= 0;
++    definer_user.length= 0;
++
++    definer_host.str= 0;
++    definer_host.length= 0;
++  }
++
++  stmt_query.append(STRING_WITH_LEN("CREATE "));
++
++  append_definer(thd, &stmt_query, &definer_user, &definer_host);
++
++  LEX_STRING stmt_definition;
++  stmt_definition.str= (char*) thd->lex->stmt_definition_begin;
++  stmt_definition.length= thd->lex->stmt_definition_end
++    - thd->lex->stmt_definition_begin;
++  trim_whitespace(thd->charset(), & stmt_definition);
++
++  stmt_query.append(stmt_definition.str, stmt_definition.length);
++
++  return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), 
++                             buf, buf_len);
++}
++#endif /* WITH_WSREP */
+diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
+index 4d3d4e9..3b6173b 100644
+--- a/sql/sql_truncate.cc
++++ b/sql/sql_truncate.cc
+@@ -24,6 +24,9 @@
+ #include "sql_parse.h"   // check_one_table_access()
+ #include "sql_truncate.h"
+ #include "sql_show.h"    //append_identifier()
++#ifdef WITH_WSREP
++#include "wsrep_mysqld.h"
++#endif /* WITH_WSREP */
+ /**
+@@ -461,6 +464,12 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
+   {
+     bool hton_can_recreate;
++#ifdef WITH_WSREP
++    if (WSREP(thd) && wsrep_to_isolation_begin(thd, 
++                                                table_ref->db, 
++                                                table_ref->table_name, NULL))
++        DBUG_RETURN(TRUE);
++#endif /* WITH_WSREP */
+     if (lock_table(thd, table_ref, &hton_can_recreate))
+       DBUG_RETURN(TRUE);
+@@ -542,7 +551,6 @@ bool Sql_cmd_truncate_table::execute(THD *thd)
+   if (! (res= truncate_table(thd, first_table)))
+     my_ok(thd);
+-
+   DBUG_RETURN(res);
+ }
+diff --git a/sql/sql_update.cc b/sql/sql_update.cc
+index 4c4714e..cb34af5 100644
+--- a/sql/sql_update.cc
++++ b/sql/sql_update.cc
+@@ -988,7 +988,11 @@ int mysql_update(THD *thd,
+   */
+   if ((error < 0) || thd->transaction.stmt.cannot_safely_rollback())
+   {
++#ifdef WITH_WSREP
++    if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       int errcode= 0;
+       if (error < 0)
+@@ -2203,7 +2207,11 @@ void multi_update::abort_result_set()
+       The query has to binlog because there's a modified non-transactional table
+       either from the query's list or via a stored routine: bug#13270,23333
+     */
++#ifdef WITH_WSREP
++    if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       /*
+         THD::killed status might not have been set ON at time of an error
+@@ -2435,7 +2443,11 @@ bool multi_update::send_eof()
+   if (local_error == 0 || thd->transaction.stmt.cannot_safely_rollback())
+   {
++#ifdef WITH_WSREP
++    if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
++#else
+     if (mysql_bin_log.is_open())
++#endif
+     {
+       int errcode= 0;
+       if (local_error == 0)
+diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
+index 180b7cd..4b6ef7a 100644
+--- a/sql/sql_yacc.yy
++++ b/sql/sql_yacc.yy
+@@ -7433,7 +7433,7 @@ alter:
+           }
+           view_tail
+           {}
+-        | ALTER definer_opt EVENT_SYM sp_name
++        | ALTER definer_opt remember_name EVENT_SYM sp_name
+           {
+             /* 
+               It is safe to use Lex->spname because
+@@ -7445,9 +7445,12 @@ alter:
+             if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
+               MYSQL_YYABORT;
+-            Lex->event_parse_data->identifier= $4;
++            Lex->event_parse_data->identifier= $5;
+             Lex->sql_command= SQLCOM_ALTER_EVENT;
++#ifdef WITH_WSREP
++            Lex->stmt_definition_begin= $3;
++#endif
+           }
+           ev_alter_on_schedule_completion
+           opt_ev_rename_to
+@@ -7455,7 +7458,7 @@ alter:
+           opt_ev_comment
+           opt_ev_sql_stmt
+           {
+-            if (!($6 || $7 || $8 || $9 || $10))
++            if (!($7 || $8 || $9 || $10 || $11))
+             {
+               my_parse_error(ER(ER_SYNTAX_ERROR));
+               MYSQL_YYABORT;
+@@ -7465,6 +7468,9 @@ alter:
+               can overwrite it
+             */
+             Lex->sql_command= SQLCOM_ALTER_EVENT;
++#ifdef WITH_WSREP
++            Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr();
++#endif
+           }
+         | ALTER TABLESPACE alter_tablespace_info
+           {
+diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
+index f44196e..f26605a 100644
+--- a/sql/sys_vars.cc
++++ b/sql/sys_vars.cc
+@@ -3222,6 +3222,10 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
+     if (trans_commit_stmt(thd) || trans_commit(thd))
+     {
+       thd->variables.option_bits&= ~OPTION_AUTOCOMMIT;
++      thd->mdl_context.release_transactional_locks();
++#ifdef WITH_WSREP
++      WSREP_DEBUG("autocommit, MDL TRX lock released: %lu", thd->thread_id);
++#endif /* WITH_WSREP */
+       return true;
+     }
+     /*
+@@ -4216,6 +4220,274 @@ static Sys_var_tz Sys_time_zone(
+        "time_zone", "time_zone",
+        SESSION_VAR(time_zone), NO_CMD_LINE,
+        DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
++#ifdef WITH_WSREP
++#include "wsrep_var.h"
++#include "wsrep_sst.h"
++#include "wsrep_binlog.h"
++
++static Sys_var_charptr Sys_wsrep_provider(
++       "wsrep_provider", "Path to replication provider library",
++       PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER),
++       IN_FS_CHARSET, DEFAULT(wsrep_provider), 
++       //       IN_FS_CHARSET, DEFAULT(wsrep_provider_default), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update));
++
++static Sys_var_charptr Sys_wsrep_provider_options(
++       "wsrep_provider_options", "provider specific options",
++       PREALLOCATED GLOBAL_VAR(wsrep_provider_options), 
++       CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER_OPTIONS),
++       IN_FS_CHARSET, DEFAULT(wsrep_provider_options), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_provider_options_check), 
++       ON_UPDATE(wsrep_provider_options_update));
++
++static Sys_var_charptr Sys_wsrep_data_home_dir(
++       "wsrep_data_home_dir", "home directory for wsrep provider",
++       READ_ONLY GLOBAL_VAR(wsrep_data_home_dir), CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(""), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG);
++
++static Sys_var_charptr Sys_wsrep_cluster_name(
++       "wsrep_cluster_name", "Name for the cluster",
++       PREALLOCATED GLOBAL_VAR(wsrep_cluster_name), CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_cluster_name), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_cluster_name_check),
++       ON_UPDATE(wsrep_cluster_name_update));
++
++static PolyLock_mutex PLock_wsrep_slave_threads(&LOCK_wsrep_slave_threads);
++static Sys_var_charptr Sys_wsrep_cluster_address (
++       "wsrep_cluster_address", "Address to initially connect to cluster",
++       PREALLOCATED GLOBAL_VAR(wsrep_cluster_address), 
++       CMD_LINE(REQUIRED_ARG, OPT_WSREP_CLUSTER_ADDRESS),
++       IN_FS_CHARSET, DEFAULT(wsrep_cluster_address),
++       &PLock_wsrep_slave_threads, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_cluster_address_check), 
++       ON_UPDATE(wsrep_cluster_address_update));
++
++static Sys_var_charptr Sys_wsrep_node_name (
++       "wsrep_node_name", "Node name",
++       PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_node_name), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG);
++
++static Sys_var_charptr Sys_wsrep_node_address (
++       "wsrep_node_address", "Node address",
++       PREALLOCATED GLOBAL_VAR(wsrep_node_address), CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_node_address), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_node_address_check), 
++       ON_UPDATE(wsrep_node_address_update));
++
++static Sys_var_charptr Sys_wsrep_node_incoming_address(
++       "wsrep_node_incoming_address", "Client connection address",
++       PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_node_incoming_address), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG);
++
++static Sys_var_ulong Sys_wsrep_slave_threads(
++       "wsrep_slave_threads", "Number of slave appliers to launch",
++       GLOBAL_VAR(wsrep_slave_threads), CMD_LINE(REQUIRED_ARG),
++       VALID_RANGE(1, 512), DEFAULT(1), BLOCK_SIZE(1),
++       &PLock_wsrep_slave_threads, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_slave_threads_check), 
++       ON_UPDATE(wsrep_slave_threads_update));
++
++static Sys_var_charptr Sys_wsrep_dbug_option(
++       "wsrep_dbug_option", "DBUG options to provider library",
++       GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(""),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG);
++
++static Sys_var_mybool Sys_wsrep_debug(
++       "wsrep_debug", "To enable debug level logging",
++       GLOBAL_VAR(wsrep_debug), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_convert_LOCK_to_trx(
++       "wsrep_convert_LOCK_to_trx", "To convert locking sessions "
++       "into transactions",
++       GLOBAL_VAR(wsrep_convert_LOCK_to_trx), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_ulong Sys_wsrep_retry_autocommit(
++      "wsrep_retry_autocommit", "Max number of times to retry "
++      "a failed autocommit statement",
++       SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG),
++       VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1));
++
++static Sys_var_mybool Sys_wsrep_auto_increment_control(
++       "wsrep_auto_increment_control", "To automatically control the "
++       "assignment of autoincrement variables",
++       GLOBAL_VAR(wsrep_auto_increment_control), 
++       CMD_LINE(OPT_ARG), DEFAULT(TRUE));
++
++static Sys_var_mybool Sys_wsrep_drupal_282555_workaround(
++       "wsrep_drupal_282555_workaround", "To use a workaround for"
++       "bad autoincrement value", 
++       GLOBAL_VAR(wsrep_drupal_282555_workaround), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_charptr sys_wsrep_sst_method(
++       "wsrep_sst_method", "State snapshot transfer method",
++       GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_sst_method), NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_sst_method_check),
++       ON_UPDATE(wsrep_sst_method_update)); 
++
++static Sys_var_charptr Sys_wsrep_sst_receive_address( 
++       "wsrep_sst_receive_address", "Address where node is waiting for "
++       "SST contact", 
++       GLOBAL_VAR(wsrep_sst_receive_address),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(wsrep_sst_receive_address), NO_MUTEX_GUARD, 
++       NOT_IN_BINLOG,
++       ON_CHECK(wsrep_sst_receive_address_check),
++       ON_UPDATE(wsrep_sst_receive_address_update)); 
++
++static Sys_var_charptr Sys_wsrep_sst_auth(
++       "wsrep_sst_auth", "Authentication for SST connection",
++       PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG, OPT_WSREP_SST_AUTH),
++       IN_FS_CHARSET, DEFAULT(wsrep_sst_auth), NO_MUTEX_GUARD, 
++       NOT_IN_BINLOG,
++       ON_CHECK(wsrep_sst_auth_check),
++       ON_UPDATE(wsrep_sst_auth_update)); 
++
++static Sys_var_charptr Sys_wsrep_sst_donor(
++       "wsrep_sst_donor", "preferred donor node for the SST",
++       GLOBAL_VAR(wsrep_sst_donor),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_sst_donor_check),
++       ON_UPDATE(wsrep_sst_donor_update)); 
++
++static Sys_var_mybool Sys_wsrep_sst_donor_rejects_queries(
++       "wsrep_sst_donor_rejects_queries", "Reject client queries "
++       "when donating state snapshot transfer", 
++       GLOBAL_VAR(wsrep_sst_donor_rejects_queries), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_on (
++       "wsrep_on", "To enable wsrep replication ",
++       SESSION_VAR(wsrep_on), 
++       CMD_LINE(OPT_ARG), DEFAULT(TRUE), 
++       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
++       ON_UPDATE(wsrep_on_update));
++
++static Sys_var_charptr Sys_wsrep_start_position (
++       "wsrep_start_position", "global transaction position to start from ",
++       PREALLOCATED GLOBAL_VAR(wsrep_start_position), 
++       CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION),
++       IN_FS_CHARSET, DEFAULT(wsrep_start_position),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_start_position_check), 
++       ON_UPDATE(wsrep_start_position_update));
++
++static Sys_var_ulong Sys_wsrep_max_ws_size (
++       "wsrep_max_ws_size", "Max write set size (bytes)",
++       GLOBAL_VAR(wsrep_max_ws_size), CMD_LINE(REQUIRED_ARG),
++       /* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */
++       VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1));
++
++static Sys_var_ulong Sys_wsrep_max_ws_rows (
++       "wsrep_max_ws_rows", "Max number of rows in write set",
++       GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG),
++       VALID_RANGE(1, 1048576), DEFAULT(131072), BLOCK_SIZE(1));
++
++static Sys_var_charptr Sys_wsrep_notify_cmd(
++       "wsrep_notify_cmd", "",
++       GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG),
++       IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG);
++
++static Sys_var_mybool Sys_wsrep_certify_nonPK(
++       "wsrep_certify_nonPK", "Certify tables with no primary key",
++       GLOBAL_VAR(wsrep_certify_nonPK), 
++       CMD_LINE(OPT_ARG), DEFAULT(TRUE));
++
++static Sys_var_mybool Sys_wsrep_causal_reads(
++       "wsrep_causal_reads", "(DEPRECATED) setting this variable is equivalent to setting wsrep_sync_wait READ flag",
++       SESSION_VAR(wsrep_causal_reads), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
++       ON_UPDATE(wsrep_causal_reads_update));
++
++static Sys_var_uint Sys_wsrep_sync_wait(
++       "wsrep_sync_wait", "Ensure \"synchronous\" read view before executing an operation of the type specified by bitmask: 1 - READ(includes SELECT, SHOW and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - INSERT and REPLACE",
++       SESSION_VAR(wsrep_sync_wait),
++       CMD_LINE(OPT_ARG),
++       VALID_RANGE(WSREP_SYNC_WAIT_NONE, WSREP_SYNC_WAIT_MAX),
++       DEFAULT(WSREP_SYNC_WAIT_NONE),
++       BLOCK_SIZE(1),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
++       ON_UPDATE(wsrep_sync_wait_update));
++
++static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS };
++static Sys_var_enum Sys_wsrep_OSU_method(
++       "wsrep_OSU_method", "Method for Online Schema Upgrade",
++       GLOBAL_VAR(wsrep_OSU_method_options), CMD_LINE(OPT_ARG),
++       wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
++       ON_UPDATE(0));
++
++static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync);
++static Sys_var_mybool Sys_wsrep_desync (
++       "wsrep_desync", "To desynchronize the node from the cluster",
++       GLOBAL_VAR(wsrep_desync), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE),
++       &PLock_wsrep_desync, NOT_IN_BINLOG,
++       ON_CHECK(wsrep_desync_check),
++       ON_UPDATE(wsrep_desync_update));
++
++static Sys_var_enum Sys_wsrep_forced_binlog_format(
++       "wsrep_forced_binlog_format", "binlog format to take effect over user's choice",
++       GLOBAL_VAR(wsrep_forced_binlog_format), 
++       CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT),
++       wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC),
++       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
++       ON_UPDATE(0));
++
++static Sys_var_mybool Sys_wsrep_recover_datadir(
++       "wsrep_recover", "Recover database state after crash and exit",
++       READ_ONLY GLOBAL_VAR(wsrep_recovery),
++       CMD_LINE(OPT_ARG, OPT_WSREP_RECOVER), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_replicate_myisam(
++       "wsrep_replicate_myisam", "To enable myisam replication",
++       GLOBAL_VAR(wsrep_replicate_myisam), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_log_conflicts(
++       "wsrep_log_conflicts", "To log multi-master conflicts",
++       GLOBAL_VAR(wsrep_log_conflicts), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_ulong Sys_wsrep_mysql_replication_bundle(
++      "wsrep_mysql_replication_bundle", "mysql replication group commit ",
++       GLOBAL_VAR(wsrep_mysql_replication_bundle), CMD_LINE(REQUIRED_ARG),
++       VALID_RANGE(0, 1000), DEFAULT(0), BLOCK_SIZE(1));
++
++static Sys_var_mybool Sys_wsrep_preordered(
++       "wsrep_preordered", "To enable preordered write set processing",
++       GLOBAL_VAR(wsrep_preordered_opt), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_load_data_splitting(
++       "wsrep_load_data_splitting", "To commit LOAD DATA "
++       "transaction after every 10K rows inserted",
++       GLOBAL_VAR(wsrep_load_data_splitting), 
++       CMD_LINE(OPT_ARG), DEFAULT(TRUE));
++
++static Sys_var_mybool Sys_wsrep_slave_FK_checks(
++       "wsrep_slave_FK_checks", "Should slave thread do "
++       "foreign key constraint checks",
++       GLOBAL_VAR(wsrep_slave_FK_checks), 
++       CMD_LINE(OPT_ARG), DEFAULT(TRUE));
++
++static Sys_var_mybool Sys_wsrep_slave_UK_checks(
++       "wsrep_slave_UK_checks", "Should slave thread do "
++       "secondary index uniqueness chesks",
++       GLOBAL_VAR(wsrep_slave_UK_checks), 
++       CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++
++static Sys_var_mybool Sys_wsrep_restart_slave(
++       "wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster",
++       GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
++#endif /* WITH_WSREP */
+ static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)
+ {
+diff --git a/sql/table.cc b/sql/table.cc
+index afd3947..95eb03d 100644
+--- a/sql/table.cc
++++ b/sql/table.cc
+@@ -5321,8 +5321,17 @@ void TABLE::mark_columns_needed_for_delete()
+         in mark_columns_per_binlog_row_image, if not, then use
+         the hidden primary key
+       */
++#ifdef WITH_WSREP
++      /* this does not affect wsrep patch as long as we use RBR only,
++       but this condition is just preparing for possible future STATEMENT 
++       format support
++      */
++      if (!((WSREP_EMULATE_BINLOG(current_thd) || mysql_bin_log.is_open()) && 
++          in_use && in_use->is_current_stmt_binlog_format_row()))
++#else
+       if (!(mysql_bin_log.is_open() && in_use &&
+           in_use->is_current_stmt_binlog_format_row()))
++#endif /* WITH_WSREP */
+         file->use_hidden_primary_key();
+     }
+     else
+@@ -5388,8 +5397,17 @@ void TABLE::mark_columns_needed_for_update()
+         in mark_columns_per_binlog_row_image, if not, then use
+         the hidden primary key
+       */
++#ifdef WITH_WSREP
++      /* this does not affect wsrep patch as long as we use RBR only,
++       but this condition is just preparing for possible future STATEMENT 
++       format support
++      */
++      if (!((WSREP_EMULATE_BINLOG(current_thd) || mysql_bin_log.is_open()) && 
++          in_use && in_use->is_current_stmt_binlog_format_row()))
++#else
+       if (!(mysql_bin_log.is_open() && in_use &&
+           in_use->is_current_stmt_binlog_format_row()))
++#endif /* WITH_WSREP */
+         file->use_hidden_primary_key();
+     }
+     else
+@@ -5441,9 +5459,15 @@ void TABLE::mark_columns_per_binlog_row_image()
+     If in RBR we may need to mark some extra columns,
+     depending on the binlog-row-image command line argument.
+    */
++#ifdef WITH_WSREP
++  if (((WSREP_EMULATE_BINLOG(current_thd) || mysql_bin_log.is_open()) && 
++       in_use && in_use->is_current_stmt_binlog_format_row()          &&
++       !ha_check_storage_engine_flag(s->db_type(), HTON_NO_BINLOG_ROW_OPT)))
++#else
+   if ((mysql_bin_log.is_open() && in_use &&
+        in_use->is_current_stmt_binlog_format_row() &&
+        !ha_check_storage_engine_flag(s->db_type(), HTON_NO_BINLOG_ROW_OPT)))
++#endif /* WITH_WSREP */
+   {
+     THD *thd= current_thd;
+diff --git a/sql/transaction.cc b/sql/transaction.cc
+index a307e8a..1247917 100644
+--- a/sql/transaction.cc
++++ b/sql/transaction.cc
+@@ -102,6 +102,9 @@ static bool xa_trans_force_rollback(THD *thd)
+     by ha_rollback()/THD::transaction::cleanup().
+   */
+   thd->transaction.xid_state.rm_error= 0;
++#ifdef WITH_WSREP
++  wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+   if (ha_rollback_trans(thd, true))
+   {
+     my_error(ER_XAER_RMERR, MYF(0));
+@@ -140,10 +143,16 @@ bool trans_begin(THD *thd, uint flags)
+       (thd->variables.option_bits & OPTION_TABLE_LOCK))
+   {
+     thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
++#ifdef WITH_WSREP
++    wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+     thd->server_status&=
+       ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+     DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+     res= MY_TEST(ha_commit_trans(thd, TRUE));
++#ifdef WITH_WSREP
++    wsrep_post_commit(thd, TRUE);
++#endif /* WITH_WSREP */
+   }
+   thd->variables.option_bits&= ~OPTION_BEGIN;
+@@ -181,6 +190,12 @@ bool trans_begin(THD *thd, uint flags)
+     thd->tx_read_only= false;
+   }
++#ifdef WITH_WSREP
++  thd->wsrep_PA_safe= true;
++  if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
++    DBUG_RETURN(TRUE);
++#endif /* WITH_WSREP */
++
+   thd->variables.option_bits|= OPTION_BEGIN;
+   thd->server_status|= SERVER_STATUS_IN_TRANS;
+   if (thd->tx_read_only)
+@@ -222,12 +237,18 @@ bool trans_commit(THD *thd)
+   if (trans_check_state(thd))
+     DBUG_RETURN(TRUE);
++#ifdef WITH_WSREP
++  wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+   thd->server_status&=
+     ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+   DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+   res= ha_commit_trans(thd, TRUE);
+   thd->variables.option_bits&= ~OPTION_BEGIN;
+   thd->transaction.all.reset_unsafe_rollback_flags();
++#ifdef WITH_WSREP
++  wsrep_post_commit(thd, TRUE);
++#endif /* WITH_WSREP */
+   thd->lex->start_transaction_opt= 0;
+   DBUG_RETURN(MY_TEST(res));
+@@ -275,10 +296,16 @@ bool trans_commit_implicit(THD *thd)
+     /* Safety if one did "drop table" on locked tables */
+     if (!thd->locked_tables_mode)
+       thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
+-    thd->server_status&=
++#ifdef WITH_WSREP
++    wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
++     thd->server_status&=
+       ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+     DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+     res= MY_TEST(ha_commit_trans(thd, TRUE));
++#ifdef WITH_WSREP
++    wsrep_post_commit(thd, TRUE);
++#endif /* WITH_WSREP */
+   }
+   else if (tc_log)
+     tc_log->commit(thd, true);
+@@ -312,6 +339,9 @@ bool trans_rollback(THD *thd)
+ {
+   int res;
+   DBUG_ENTER("trans_rollback");
++#ifdef WITH_WSREP
++  thd->wsrep_PA_safe= true;
++#endif /* WITH_WSREP */
+ #ifndef DBUG_OFF
+   char buf1[256], buf2[256];
+@@ -326,6 +356,9 @@ bool trans_rollback(THD *thd)
+   if (trans_check_state(thd))
+     DBUG_RETURN(TRUE);
++#ifdef WITH_WSREP
++  wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+   thd->server_status&=
+     ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+   DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+@@ -366,6 +399,9 @@ bool trans_rollback_implicit(THD *thd)
+   */
+   DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt);
++#ifdef WITH_WSREP
++  wsrep_register_hton(thd, true);
++#endif /* WITH_WSREP */
+   thd->server_status&=
+     ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+   DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+@@ -431,12 +467,20 @@ bool trans_commit_stmt(THD *thd)
+   if (thd->transaction.stmt.ha_list)
+   {
++#ifdef WITH_WSREP
++    wsrep_register_hton(thd, FALSE);
++#endif /* WITH_WSREP */
+     res= ha_commit_trans(thd, FALSE);
+     if (! thd->in_active_multi_stmt_transaction())
++#ifdef WITH_WSREP
+     {
++#endif /* WITH_WSREP */
+       thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+       thd->tx_read_only= thd->variables.tx_read_only;
++#ifdef WITH_WSREP
++      wsrep_post_commit(thd, FALSE);
+     }
++#endif /* WITH_WSREP */
+   }
+   else if (tc_log)
+     tc_log->commit(thd, false);
+@@ -481,6 +525,9 @@ bool trans_rollback_stmt(THD *thd)
+   if (thd->transaction.stmt.ha_list)
+   {
++#ifdef WITH_WSREP
++    wsrep_register_hton(thd, FALSE);
++#endif /* WITH_WSREP */
+     ha_rollback_trans(thd, FALSE);
+     if (! thd->in_active_multi_stmt_transaction())
+     {
+@@ -652,9 +699,16 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
+     For backward-compatibility reasons we always release MDL if binary
+     logging is off.
+   */
++#ifdef WITH_WSREP
++  bool mdl_can_safely_rollback_to_savepoint=
++                (!((WSREP_EMULATE_BINLOG(thd) ||  mysql_bin_log.is_open()) 
++                 && thd->variables.sql_log_bin) ||
++                 ha_rollback_to_savepoint_can_release_mdl(thd));
++#else
+   bool mdl_can_safely_rollback_to_savepoint=
+                 (!(mysql_bin_log.is_open() && thd->variables.sql_log_bin) ||
+                  ha_rollback_to_savepoint_can_release_mdl(thd));
++#endif /* WITH_WSREP */
+   if (ha_rollback_to_savepoint(thd, sv))
+     res= TRUE;
+@@ -871,9 +925,15 @@ bool trans_xa_commit(THD *thd)
+   }
+   else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+   {
++#ifdef WITH_WSREP
++    wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+     int r= ha_commit_trans(thd, TRUE);
+     if ((res= MY_TEST(r)))
+       my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
++#ifdef WITH_WSREP
++    wsrep_post_commit(thd, TRUE);
++#endif /* WITH_WSREP */
+   }
+   else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+   {
+@@ -892,6 +952,9 @@ bool trans_xa_commit(THD *thd)
+     if (thd->mdl_context.acquire_lock(&mdl_request,
+                                       thd->variables.lock_wait_timeout))
+     {
++#ifdef WITH_WSREP
++      wsrep_register_hton(thd, TRUE);
++#endif /* WITH_WSREP */
+       ha_rollback_trans(thd, TRUE);
+       my_error(ER_XAER_RMERR, MYF(0));
+     }
+diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
+new file mode 100644
+index 0000000..bb95a66
+--- /dev/null
++++ b/sql/wsrep_applier.cc
+@@ -0,0 +1,386 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#include "wsrep_priv.h"
++#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
++
++#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
++#include "wsrep_applier.h"
++#include "debug_sync.h"
++
++/*
++  read the first event from (*buf). The size of the (*buf) is (*buf_len).
++  At the end (*buf) is shitfed to point to the following event or NULL and
++  (*buf_len) will be changed to account just being read bytes of the 1st event.
++*/
++
++static Log_event* wsrep_read_log_event(
++    char **arg_buf, size_t *arg_buf_len,
++    const Format_description_log_event *description_event)
++{
++  DBUG_ENTER("wsrep_read_log_event");
++  char *head= (*arg_buf);
++
++  uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
++  char *buf= (*arg_buf);
++  const char *error= 0;
++  Log_event *res=  0;
++
++  if (data_len > wsrep_max_ws_size)
++  {
++    error = "Event too big";
++    goto err;
++  }
++
++  res= Log_event::read_log_event(buf, data_len, &error, description_event, 0);
++
++err:
++  if (!res)
++  {
++    DBUG_ASSERT(error != 0);
++    sql_print_error("Error in Log_event::read_log_event(): "
++                    "'%s', data_len: %d, event_type: %d",
++                    error,data_len,head[EVENT_TYPE_OFFSET]);
++  }
++  (*arg_buf)+= data_len;
++  (*arg_buf_len)-= data_len;
++  DBUG_RETURN(res);
++}
++
++#include "transaction.h" // trans_commit(), trans_rollback()
++#include "rpl_rli.h"     // class Relay_log_info;
++#include "sql_base.h"    // close_temporary_table()
++
++static inline void
++wsrep_set_apply_format(THD* thd, Format_description_log_event* ev)
++{
++  if (thd->wsrep_apply_format)
++  {
++      delete (Format_description_log_event*)thd->wsrep_apply_format;
++  }
++  thd->wsrep_apply_format= ev;
++}
++
++static inline Format_description_log_event*
++wsrep_get_apply_format(THD* thd)
++{
++  if (thd->wsrep_apply_format)
++      return (Format_description_log_event*) thd->wsrep_apply_format;
++  return thd->wsrep_rli->get_rli_description_event();
++}
++
++static wsrep_cb_status_t wsrep_apply_events(THD*        thd,
++                                            const void* events_buf,
++                                            size_t      buf_len)
++{
++  char *buf= (char *)events_buf;
++  int rcode= 0;
++  int event= 1;
++
++  DBUG_ENTER("wsrep_apply_events");
++
++  if (thd->killed == THD::KILL_CONNECTION &&
++      thd->wsrep_conflict_state != REPLAYING)
++  {
++    WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld",
++               (long long) wsrep_thd_trx_seqno(thd));
++    DBUG_RETURN(WSREP_CB_FAILURE);
++  }
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  thd->wsrep_query_state= QUERY_EXEC;
++  if (thd->wsrep_conflict_state!= REPLAYING)
++    thd->wsrep_conflict_state= NO_CONFLICT;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
++                            (long long) wsrep_thd_trx_seqno(thd));
++
++  while(buf_len)
++  {
++    int exec_res;
++    Log_event* ev= wsrep_read_log_event(&buf, &buf_len,
++                                        wsrep_get_apply_format(thd));
++
++    if (!ev)
++    {
++      WSREP_ERROR("applier could not read binlog event, seqno: %lld, len: %zu",
++                  (long long)wsrep_thd_trx_seqno(thd), buf_len);
++      rcode= 1;
++      goto error;
++    }
++
++    switch (ev->get_type_code()) {
++    case FORMAT_DESCRIPTION_EVENT:
++      wsrep_set_apply_format(thd, (Format_description_log_event*)ev);
++      continue;
++    case GTID_LOG_EVENT:
++    {
++      Gtid_log_event* gev= (Gtid_log_event*)ev;
++      if (gev->get_gno() == 0)
++      {
++        /* Skip GTID log event to make binlog to generate LTID on commit */
++        delete ev;
++        continue;
++      }
++    }
++    default:
++      break;
++    }
++
++    thd->server_id = ev->server_id; // use the original server id for logging
++    thd->set_time();                // time the query
++    wsrep_xid_init(&thd->transaction.xid_state.xid,
++                   &thd->wsrep_trx_meta.gtid.uuid,
++                   thd->wsrep_trx_meta.gtid.seqno);
++    thd->lex->current_select= 0;
++    if (!ev->when.tv_sec)
++      my_micro_time_to_timeval(my_micro_time(), &ev->when);
++    ev->thd = thd;
++    exec_res = ev->apply_event(thd->wsrep_rli);
++    DBUG_PRINT("info", ("exec_event result: %d", exec_res));
++
++    if (exec_res)
++    {
++      WSREP_WARN("RBR event %d %s apply warning: %d, %lld",
++                 event, ev->get_type_str(), exec_res,
++                 (long long) wsrep_thd_trx_seqno(thd));
++      rcode= exec_res;
++      /* stop processing for the first error */
++      delete ev;
++      goto error;
++    }
++    event++;
++
++    if (thd->wsrep_conflict_state!= NO_CONFLICT &&
++        thd->wsrep_conflict_state!= REPLAYING)
++      WSREP_WARN("conflict state after RBR event applying: %d, %lld",
++                 thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd));
++
++    if (thd->wsrep_conflict_state == MUST_ABORT) {
++      WSREP_WARN("RBR event apply failed, rolling back: %lld",
++                 (long long) wsrep_thd_trx_seqno(thd));
++      trans_rollback(thd);
++      thd->locked_tables_list.unlock_locked_tables(thd);
++      /* Release transactional metadata locks. */
++      thd->mdl_context.release_transactional_locks();
++      thd->wsrep_conflict_state= NO_CONFLICT;
++      DBUG_RETURN(WSREP_CB_FAILURE);
++    }
++
++    delete ev;
++  }
++
++ error:
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  thd->wsrep_query_state= QUERY_IDLE;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  assert(thd->wsrep_exec_mode== REPL_RECV);
++
++  if (thd->killed == THD::KILL_CONNECTION)
++    WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd));
++
++  if (rcode) DBUG_RETURN(WSREP_CB_FAILURE);
++  DBUG_RETURN(WSREP_CB_SUCCESS);
++}
++
++wsrep_cb_status_t wsrep_apply_cb(void* const             ctx,
++                                 const void* const       buf,
++                                 size_t const            buf_len,
++                                 uint32_t const          flags,
++                                 const wsrep_trx_meta_t* meta)
++{
++  THD* const thd((THD*)ctx);
++
++// Allow tests to block the applier thread using the DBUG facilities
++  DBUG_EXECUTE_IF("sync.wsrep_apply_cb",
++                 {
++                   const char act[]=
++                     "now "
++                     "wait_for signal.wsrep_apply_cb";
++                   DBUG_ASSERT(!debug_sync_set_action(thd,
++                                                      STRING_WITH_LEN(act)));
++                 };);
++
++  thd->wsrep_trx_meta = *meta;
++
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "applying write set %lld: %p, %zu",
++           (long long)wsrep_thd_trx_seqno(thd), buf, buf_len);
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "applying write set");
++#endif /* WSREP_PROC_INFO */
++
++  /* tune FK and UK checking policy */
++  if (wsrep_slave_UK_checks == FALSE) 
++    thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
++  else
++    thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
++
++  if (wsrep_slave_FK_checks == FALSE) 
++    thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
++  else
++    thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
++
++  if (flags & WSREP_FLAG_ISOLATION)
++  {
++    thd->wsrep_apply_toi= true;
++    /*
++      Don't run in transaction mode with TOI actions.
++     */
++    thd->variables.option_bits&= ~OPTION_BEGIN;
++    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++  }
++  wsrep_cb_status_t rcode(wsrep_apply_events(thd, buf, buf_len));
++
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "applied write set %lld", (long long)wsrep_thd_trx_seqno(thd));
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "applied write set");
++#endif /* WSREP_PROC_INFO */
++
++  if (WSREP_CB_SUCCESS != rcode)
++  {
++    wsrep_dump_rbr_buf(thd, buf, buf_len);
++  }
++
++  TABLE *tmp;
++  while ((tmp = thd->temporary_tables))
++  {
++    WSREP_DEBUG("Applier %lu, has temporary tables: %s.%s",
++                  thd->thread_id, 
++                  (tmp->s) ? tmp->s->db.str : "void",
++                  (tmp->s) ? tmp->s->table_name.str : "void");
++      close_temporary_table(thd, tmp, 1, 1);    
++  }
++
++  return rcode;
++}
++
++static wsrep_cb_status_t wsrep_commit(THD* const thd,
++                                      wsrep_seqno_t const global_seqno)
++{
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "committing %lld", (long long)wsrep_thd_trx_seqno(thd));
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "committing");
++#endif /* WSREP_PROC_INFO */
++
++  wsrep_cb_status_t const rcode(trans_commit(thd) ?
++                                WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
++
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "committed %lld", (long long)wsrep_thd_trx_seqno(thd));
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "committed");
++#endif /* WSREP_PROC_INFO */
++
++  if (WSREP_CB_SUCCESS == rcode)
++  {
++    thd->wsrep_rli->cleanup_context(thd, 0);
++    thd->variables.gtid_next.set_automatic();
++    // TODO: mark snapshot with global_seqno.
++  }
++
++  return rcode;
++}
++
++static wsrep_cb_status_t wsrep_rollback(THD* const thd,
++                                        wsrep_seqno_t const global_seqno)
++{
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "rolling back %lld", (long long)wsrep_thd_trx_seqno(thd));
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "rolling back");
++#endif /* WSREP_PROC_INFO */
++
++  wsrep_cb_status_t const rcode(trans_rollback(thd) ?
++                                WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
++
++#ifdef WSREP_PROC_INFO
++  snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
++           "rolled back %lld", (long long)wsrep_thd_trx_seqno(thd));
++  thd_proc_info(thd, thd->wsrep_info);
++#else
++  thd_proc_info(thd, "rolled back");
++#endif /* WSREP_PROC_INFO */
++  thd->wsrep_rli->cleanup_context(thd, 0);
++  thd->variables.gtid_next.set_automatic();
++
++  return rcode;
++}
++
++wsrep_cb_status_t wsrep_commit_cb(void*         const     ctx,
++                                  uint32_t      const     flags,
++                                  const wsrep_trx_meta_t* meta,
++                                  wsrep_bool_t* const     exit,
++                                  bool          const     commit)
++{
++  THD* const thd((THD*)ctx);
++
++  assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd));
++
++  wsrep_cb_status_t rcode;
++
++  if (commit)
++    rcode = wsrep_commit(thd, meta->gtid.seqno);
++  else
++    rcode = wsrep_rollback(thd, meta->gtid.seqno);
++
++  wsrep_set_apply_format(thd, NULL);
++  thd->mdl_context.release_transactional_locks();
++  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
++  thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
++
++  if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode)
++  {
++    mysql_mutex_lock(&LOCK_wsrep_slave_threads);
++    if (wsrep_slave_count_change < 0)
++    {
++      wsrep_slave_count_change++;
++      *exit = true;
++    }
++    mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
++  }
++
++  if (*exit == false && thd->wsrep_applier)
++  {
++    /* From trans_begin() */
++    thd->variables.option_bits|= OPTION_BEGIN;
++    thd->server_status|= SERVER_STATUS_IN_TRANS;
++    thd->wsrep_apply_toi= false;
++  }
++
++  return rcode;
++}
++
++
++wsrep_cb_status_t wsrep_unordered_cb(void*       const ctx,
++                                     const void* const data,
++                                     size_t      const size)
++{
++    return WSREP_CB_SUCCESS;
++}
+diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h
+new file mode 100644
+index 0000000..816970d
+--- /dev/null
++++ b/sql/wsrep_applier.h
+@@ -0,0 +1,38 @@
++/* Copyright 2013 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#ifndef WSREP_APPLIER_H
++#define WSREP_APPLIER_H
++
++#include <sys/types.h>
++
++/* wsrep callback prototypes */
++
++wsrep_cb_status_t wsrep_apply_cb(void *ctx,
++                                 const void* buf, size_t buf_len,
++                                 uint32_t flags,
++                                 const wsrep_trx_meta_t* meta);
++
++wsrep_cb_status_t wsrep_commit_cb(void *ctx,
++                                  uint32_t flags,
++                                  const wsrep_trx_meta_t* meta,
++                                  wsrep_bool_t* exit,
++                                  bool commit);
++
++wsrep_cb_status_t wsrep_unordered_cb(void*       ctx,
++                                     const void* data,
++                                     size_t      size);
++
++#endif /* WSREP_APPLIER_H */
+diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
+new file mode 100644
+index 0000000..e33422f
+--- /dev/null
++++ b/sql/wsrep_binlog.cc
+@@ -0,0 +1,414 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#include "wsrep_binlog.h"
++#include "wsrep_priv.h"
++
++/*
++  Write the contents of a cache to a memory buffer.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++ */
++int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
++{
++  *buf= NULL;
++  *buf_len= 0;
++
++  my_off_t const saved_pos(my_b_tell(cache));
++
++  if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
++  {
++    WSREP_ERROR("failed to initialize io-cache");
++    return ER_ERROR_ON_WRITE;
++  }
++
++  uint length = my_b_bytes_in_cache(cache);
++  if (unlikely(0 == length)) length = my_b_fill(cache);
++
++  size_t total_length = 0;
++
++  if (likely(length > 0)) do
++  {
++      total_length += length;
++      /*
++        Bail out if buffer grows too large.
++        A temporary fix to avoid allocating indefinitely large buffer,
++        not a real limit on a writeset size which includes other things
++        like header and keys.
++      */
++      if (total_length > wsrep_max_ws_size)
++      {
++          WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
++                     wsrep_max_ws_size, total_length);
++          goto error;
++      }
++
++      uchar* tmp = (uchar *)my_realloc(*buf, total_length, MYF(0));
++      if (!tmp)
++      {
++          WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
++                      *buf_len, length);
++          goto error;
++      }
++      *buf = tmp;
++
++      memcpy(*buf + *buf_len, cache->read_pos, length);
++      *buf_len = total_length;
++      cache->read_pos = cache->read_end;
++  } while ((cache->file >= 0) && (length = my_b_fill(cache)));
++
++  if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++  {
++    WSREP_WARN("failed to initialize io-cache");
++    goto cleanup;
++  }
++
++  if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++  {
++    WSREP_ERROR("failed to initialize io-cache");
++    goto cleanup;
++  }
++
++  return 0;
++
++error:
++  if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++  {
++    WSREP_WARN("failed to initialize io-cache");
++  }
++cleanup:
++  my_free(*buf);
++  *buf= NULL;
++  *buf_len= 0;
++  return ER_ERROR_ON_WRITE;
++}
++
++#define STACK_SIZE 4096 /* 4K - for buffer preallocated on the stack:
++                         * many transactions would fit in there
++                         * so there is no need to reach for the heap */
++
++/* Returns minimum multiple of HEAP_PAGE_SIZE that is >= length */
++static inline size_t
++heap_size(size_t length)
++{
++    return (length + HEAP_PAGE_SIZE - 1)/HEAP_PAGE_SIZE*HEAP_PAGE_SIZE;
++}
++
++/* append data to writeset */
++static inline wsrep_status_t
++wsrep_append_data(wsrep_t*           const wsrep,
++                  wsrep_ws_handle_t* const ws,
++                  const void*        const data,
++                  size_t             const len)
++{
++    struct wsrep_buf const buff = { data, len };
++    wsrep_status_t const rc(wsrep->append_data(wsrep, ws, &buff, 1,
++                                               WSREP_DATA_ORDERED, true));
++    if (rc != WSREP_OK)
++    {
++        WSREP_WARN("append_data() returned %d", rc);
++    }
++
++    return rc;
++}
++
++/*
++  Write the contents of a cache to wsrep provider.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++
++  This version reads all of cache into single buffer and then appends to a
++  writeset at once.
++ */
++static int wsrep_write_cache_once(wsrep_t*  const wsrep,
++                                  THD*      const thd,
++                                  IO_CACHE* const cache,
++                                  size_t*   const len)
++{
++    my_off_t const saved_pos(my_b_tell(cache));
++
++    if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
++    {
++        WSREP_ERROR("failed to initialize io-cache");
++        return ER_ERROR_ON_WRITE;
++    }
++
++    int err(WSREP_OK);
++
++    size_t total_length(0);
++    uchar  stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/
++    uchar* heap_buf(NULL);
++    uchar* buf(stack_buf);
++    size_t allocated(sizeof(stack_buf));
++    size_t used(0);
++
++    uint length(my_b_bytes_in_cache(cache));
++    if (unlikely(0 == length)) length = my_b_fill(cache);
++
++    if (likely(length > 0)) do
++    {
++        total_length += length;
++        /*
++          Bail out if buffer grows too large.
++          A temporary fix to avoid allocating indefinitely large buffer,
++          not a real limit on a writeset size which includes other things
++          like header and keys.
++        */
++        if (unlikely(total_length > wsrep_max_ws_size))
++        {
++            WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
++                       wsrep_max_ws_size, total_length);
++          err = WSREP_TRX_SIZE_EXCEEDED;
++            goto cleanup;
++        }
++
++        if (total_length > allocated)
++        {
++            size_t const new_size(heap_size(total_length));
++            uchar* tmp = (uchar *)my_realloc(heap_buf, new_size, MYF(0));
++            if (!tmp)
++            {
++                WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
++                            allocated, length);
++                err = WSREP_TRX_SIZE_EXCEEDED;
++                goto cleanup;
++            }
++
++            heap_buf = tmp;
++            buf = heap_buf;
++            allocated = new_size;
++
++            if (used <= STACK_SIZE && used > 0) // there's data in stack_buf
++            {
++                DBUG_ASSERT(buf == stack_buf);
++                memcpy(heap_buf, stack_buf, used);
++            }
++        }
++
++        memcpy(buf + used, cache->read_pos, length);
++        used = total_length;
++        cache->read_pos = cache->read_end;
++    } while ((cache->file >= 0) && (length = my_b_fill(cache)));
++
++    if (used > 0)
++        err = wsrep_append_data(wsrep, &thd->wsrep_ws_handle, buf, used);
++
++    if (WSREP_OK == err) *len = total_length;
++
++cleanup:
++    if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++    {
++        WSREP_ERROR("failed to reinitialize io-cache");
++    }
++
++    if (unlikely(WSREP_OK != err)) wsrep_dump_rbr_buf(thd, buf, used);
++
++    my_free(heap_buf);
++    return err;
++}
++
++/*
++  Write the contents of a cache to wsrep provider.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++
++  This version uses incremental data appending as it reads it from cache.
++ */
++static int wsrep_write_cache_inc(wsrep_t*  const wsrep,
++                                 THD*      const thd,
++                                 IO_CACHE* const cache,
++                                 size_t*   const len)
++{
++    my_off_t const saved_pos(my_b_tell(cache));
++
++    if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
++    {
++      WSREP_ERROR("failed to initialize io-cache");
++      return WSREP_TRX_ERROR;
++    }
++
++    int err(WSREP_OK);
++
++    size_t total_length(0);
++
++    uint length(my_b_bytes_in_cache(cache));
++    if (unlikely(0 == length)) length = my_b_fill(cache);
++
++    if (likely(length > 0)) do
++    {
++        total_length += length;
++        /* bail out if buffer grows too large
++           not a real limit on a writeset size which includes other things
++           like header and keys.
++        */
++        if (unlikely(total_length > wsrep_max_ws_size))
++        {
++            WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
++                       wsrep_max_ws_size, total_length);
++            err = WSREP_TRX_SIZE_EXCEEDED;
++            goto cleanup;
++        }
++
++        if(WSREP_OK != (err=wsrep_append_data(wsrep, &thd->wsrep_ws_handle,
++                                              cache->read_pos, length)))
++                goto cleanup;
++
++        cache->read_pos = cache->read_end;
++    } while ((cache->file >= 0) && (length = my_b_fill(cache)));
++
++    if (WSREP_OK == err) *len = total_length;
++
++cleanup:
++    if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++    {
++        WSREP_ERROR("failed to reinitialize io-cache");
++    }
++
++    return err;
++}
++
++/*
++  Write the contents of a cache to wsrep provider.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++ */
++int wsrep_write_cache(wsrep_t*  const wsrep,
++                      THD*      const thd,
++                      IO_CACHE* const cache,
++                      size_t*   const len)
++{
++    if (wsrep_incremental_data_collection) {
++        return wsrep_write_cache_inc(wsrep, thd, cache, len);
++    }
++    else {
++        return wsrep_write_cache_once(wsrep, thd, cache, len);
++    }
++}
++
++void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
++{
++  char filename[PATH_MAX]= {0};
++  int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log",
++                    wsrep_data_home_dir, thd->thread_id,
++                    (long long)wsrep_thd_trx_seqno(thd));
++  if (len >= PATH_MAX)
++  {
++    WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
++    return;
++  }
++
++  FILE *of= fopen(filename, "wb");
++  if (of)
++  {
++    fwrite (rbr_buf, buf_len, 1, of);
++    fclose(of);
++  }
++  else
++  {
++    WSREP_ERROR("Failed to open file '%s': %d (%s)",
++                filename, errno, strerror(errno));
++  }
++}
++
++void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache)
++{
++  char filename[PATH_MAX]= {0};
++  int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log",
++                    wsrep_data_home_dir, thd->thread_id,
++                    (long long)wsrep_thd_trx_seqno(thd));
++  size_t bytes_in_cache = 0;
++  // check path
++  if (len >= PATH_MAX)
++  {
++    WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
++    return ;
++  }
++  // init cache
++  my_off_t const saved_pos(my_b_tell(cache));
++  if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
++  {
++    WSREP_ERROR("failed to initialize io-cache");
++    return ;
++  }
++  // open file
++  FILE* of = fopen(filename, "wb");
++  if (!of)
++  {
++    WSREP_ERROR("Failed to open file '%s': %d (%s)",
++                filename, errno, strerror(errno));
++    goto cleanup;
++  }
++  // ready to write
++  bytes_in_cache= my_b_bytes_in_cache(cache);
++  if (unlikely(bytes_in_cache == 0)) bytes_in_cache = my_b_fill(cache);
++  if (likely(bytes_in_cache > 0)) do
++  {
++    if (my_fwrite(of, cache->read_pos, bytes_in_cache,
++                  MYF(MY_WME | MY_NABP)) == (size_t) -1)
++    {
++      WSREP_ERROR("Failed to write file '%s'", filename);
++      goto cleanup;
++    }
++    cache->read_pos= cache->read_end;
++  } while ((cache->file >= 0) && (bytes_in_cache= my_b_fill(cache)));
++  if(cache->error == -1)
++  {
++    WSREP_ERROR("RBR inconsistent");
++    goto cleanup;
++  }
++cleanup:
++  // init back
++  if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
++  {
++    WSREP_ERROR("failed to reinitialize io-cache");
++  }
++  // close file
++  if (of) fclose(of);
++}
++
++extern handlerton *binlog_hton;
++
++/*
++  wsrep exploits binlog's caches even if binlogging itself is not
++  activated. In such case connection close needs calling
++  actual binlog's method.
++  Todo: split binlog hton from its caches to use ones by wsrep
++  without referring to binlog's stuff.
++*/
++int wsrep_binlog_close_connection(THD* thd)
++{
++  DBUG_ENTER("wsrep_binlog_close_connection");
++  if (thd_get_ha_data(thd, binlog_hton) != NULL)
++    binlog_hton->close_connection (binlog_hton, thd);
++  DBUG_RETURN(0);
++}
++
++int wsrep_binlog_savepoint_set(THD *thd,  void *sv)
++{
++  if (!wsrep_emulate_bin_log) return 0;
++  int rcode = binlog_hton->savepoint_set(binlog_hton, thd, sv);
++  return rcode;
++}
++
++int wsrep_binlog_savepoint_rollback(THD *thd, void *sv)
++{
++  if (!wsrep_emulate_bin_log) return 0;
++  int rcode = binlog_hton->savepoint_rollback(binlog_hton, thd, sv);
++  return rcode;
++}
+diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h
+new file mode 100644
+index 0000000..a7b680f
+--- /dev/null
++++ b/sql/wsrep_binlog.h
+@@ -0,0 +1,56 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#ifndef WSREP_BINLOG_H
++#define WSREP_BINLOG_H
++
++#include "sql_class.h" // THD, IO_CACHE
++
++#define HEAP_PAGE_SIZE 65536 /* 64K */
++#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE)
++
++/*
++  Write the contents of a cache to a memory buffer.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++ */
++int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len);
++
++/*
++  Write the contents of a cache to wsrep provider.
++
++  This function quite the same as MYSQL_BIN_LOG::write_cache(),
++  with the exception that here we write in buffer instead of log file.
++
++  @param len  total amount of data written
++  @return     wsrep error status
++ */
++int wsrep_write_cache (wsrep_t*  wsrep,
++                       THD*      thd,
++                       IO_CACHE* cache,
++                       size_t*   len);
++
++/* Dump replication buffer to disk */
++void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len);
++
++/* Dump replication buffer to disk without intermediate buffer */
++void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache);
++
++int wsrep_binlog_close_connection(THD* thd);
++int wsrep_binlog_savepoint_set(THD *thd,  void *sv);
++int wsrep_binlog_savepoint_rollback(THD *thd, void *sv);
++
++#endif /* WSREP_BINLOG_H */
+diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc
+new file mode 100644
+index 0000000..5ec18c7
+--- /dev/null
++++ b/sql/wsrep_check_opts.cc
+@@ -0,0 +1,379 @@
++/* Copyright 2011 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++//#include <mysqld.h>
++#include <sql_class.h>
++//#include <sql_plugin.h>
++//#include <set_var.h>
++
++#include "wsrep_mysqld.h"
++
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <ctype.h>
++
++/* This file is about checking for correctness of mysql configuration options */
++
++struct opt
++{
++    const char* const name;
++    const char*       value;
++};
++
++/* A list of options to check.
++ * At first we assume default values and then see if they are changed on CLI or
++ * in my.cnf */
++static struct opt opts[] =
++{
++    { "wsrep_slave_threads",     "1" }, // mysqld.cc
++    { "bind_address",      "0.0.0.0" }, // mysqld.cc
++    { "wsrep_sst_method",    "rsync" }, // mysqld.cc
++    { "wsrep_sst_receive_address","AUTO"}, // mysqld.cc
++    { "binlog_format",         "ROW" }, // mysqld.cc
++    { "wsrep_provider",       "none" }, // mysqld.cc
++    { "query_cache_type",        "0" }, // mysqld.cc
++    { "query_cache_size",        "0" }, // mysqld.cc
++    { "locked_in_memory",        "0" }, // mysqld.cc
++    { "wsrep_cluster_address",   "0" }, // mysqld.cc
++    { "locks_unsafe_for_binlog", "0" }, // ha_innodb.cc
++    { "autoinc_lock_mode",       "1" }, // ha_innodb.cc
++    { 0, 0 }
++};
++
++enum
++{
++    WSREP_SLAVE_THREADS,
++    BIND_ADDRESS,
++    WSREP_SST_METHOD,
++    WSREP_SST_RECEIVE_ADDRESS,
++    BINLOG_FORMAT,
++    WSREP_PROVIDER,
++    QUERY_CACHE_TYPE,
++    QUERY_CACHE_SIZE,
++    LOCKED_IN_MEMORY,
++    WSREP_CLUSTER_ADDRESS,
++    LOCKS_UNSAFE_FOR_BINLOG,
++    AUTOINC_LOCK_MODE
++};
++
++
++/* A class to make a copy of argv[] vector */
++struct argv_copy
++{
++    int    const argc_;
++    char**       argv_;
++
++    argv_copy (int const argc, const char* const argv[]) :
++        argc_ (argc),
++        argv_ (reinterpret_cast<char**>(calloc(argc_, sizeof(char*))))
++    {
++        if (argv_)
++        {
++            for (int i = 0; i < argc_; ++i)
++            {
++                argv_[i] = strdup(argv[i]);
++
++                if (!argv_[i])
++                {
++                    argv_free (); // free whatever bee allocated
++                    return;
++                }
++            }
++        }
++    }
++
++    ~argv_copy () { argv_free (); }
++
++private:
++    argv_copy (const argv_copy&);
++    argv_copy& operator= (const argv_copy&);
++
++    void argv_free()
++    {
++        if (argv_)
++        {
++            for (int i = 0; (i < argc_) && argv_[i] ; ++i) free (argv_[i]);
++            free (argv_);
++            argv_ = 0;
++        }
++    }
++};
++
++/* a short corresponding to '--' byte sequence */
++static short const long_opt_prefix ('-' + ('-' << 8));
++
++/* Normalizes long options to have '_' instead of '-' */
++static int
++normalize_opts (argv_copy& a)
++{
++    if (a.argv_)
++    {
++        for (int i = 0; i < a.argc_; ++i)
++        {
++            char* ptr = a.argv_[i];
++            if (long_opt_prefix == *(short*)ptr) // long option
++            {
++                ptr += 2;
++                const char* end = strchr(ptr, '=');
++
++                if (!end) end = ptr + strlen(ptr);
++
++                for (; ptr != end; ++ptr) if ('-' == *ptr) *ptr = '_';
++            }
++        }
++
++        return 0;
++    }
++
++    return EINVAL;
++}
++
++/* Find required options in the argument list and change their values */
++static int
++find_opts (argv_copy& a, struct opt* const opts)
++{
++    for (int i = 0; i < a.argc_; ++i)
++    {
++        char* ptr = a.argv_[i] + 2; // we're interested only in long options
++
++        struct opt* opt = opts;
++        for (; 0 != opt->name; ++opt)
++        {
++            if (!strstr(ptr, opt->name)) continue; // try next option
++
++            /* 1. try to find value after the '=' */
++            opt->value = strchr(ptr, '=') + 1;
++
++            /* 2. if no '=', try next element in the argument vector */
++            if (reinterpret_cast<void*>(1) == opt->value)
++            {
++                /* also check that the next element is not an option itself */
++                if (i + 1 < a.argc_ && *(a.argv_[i + 1]) != '-')
++                {
++                    ++i;
++                    opt->value = a.argv_[i];
++                }
++                else opt->value = ""; // no value supplied (like boolean opt)
++            }
++
++            break; // option found, break inner loop
++        }
++    }
++
++    return 0;
++}
++
++/* Parses string for an integer. Returns 0 on success. */
++int get_long_long (const struct opt& opt, long long* const val, int const base)
++{
++    const char* const str = opt.value;
++
++    if ('\0' != *str)
++    {
++        char* endptr;
++
++        *val = strtoll (str, &endptr, base);
++
++        if ('k' == *endptr || 'K' == *endptr) 
++        { 
++            *val *= 1024L;
++            endptr++;
++        } 
++        else if ('m' == *endptr || 'M' == *endptr) 
++        {
++            *val *= 1024L * 1024L;
++            endptr++;
++        }
++        else if ('g' == *endptr || 'G' == *endptr) 
++        {
++            *val *= 1024L * 1024L * 1024L;
++            endptr++;
++        }
++
++        if ('\0' == *endptr) return 0; // the whole string was a valid integer
++    }
++
++    WSREP_ERROR ("Bad value for *%s: '%s'. Should be integer.",
++                 opt.name, opt.value);
++
++    return EINVAL;
++}
++
++/* This is flimzy coz hell knows how mysql interprets boolean strings...
++ * and, no, I'm not going to become versed in how mysql handles options -
++ * I'd rather sing.
++
++ Aha, http://dev.mysql.com/doc/refman/5.1/en/dynamic-system-variables.html:
++ Variables that have a type of “boolean” can be set to 0, 1, ON or OFF. (If you
++ set them on the command line or in an option file, use the numeric values.)
++
++ So it is '0' for FALSE, '1' or empty string for TRUE
++
++ */
++int get_bool (const struct opt& opt, bool* const val)
++{
++    const char* str = opt.value;
++
++    while (isspace(*str)) ++str; // skip initial whitespaces
++
++    ssize_t str_len = strlen(str);
++    switch (str_len)
++    {
++    case 0:
++        *val = true;
++        return 0;
++    case 1:
++        if ('0' == *str || '1' == *str)
++        {
++            *val = ('1' == *str);
++            return 0;
++        }
++    }
++
++    WSREP_ERROR ("Bad value for *%s: '%s'. Should be '0', '1' or empty string.",
++                 opt.name, opt.value);
++
++    return EINVAL;
++}
++
++static int
++check_opts (int const argc, const char* const argv[], struct opt opts[])
++{
++    /* First, make a copy of argv to be able to manipulate it */
++    argv_copy a(argc, argv);
++
++    if (!a.argv_)
++    {
++        WSREP_ERROR ("Could not copy argv vector: not enough memory.");
++        return ENOMEM;
++    }
++
++    int err = normalize_opts (a);
++    if (err)
++    {
++        WSREP_ERROR ("Failed to normalize options.");
++        return err;
++    }
++
++    err = find_opts (a, opts);
++    if (err)
++    {
++        WSREP_ERROR ("Failed to parse options.");
++        return err;
++    }
++
++    /* At this point we have updated default values in our option list to
++       what has been specified on the command line / my.cnf */
++
++    long long slave_threads;
++    err = get_long_long (opts[WSREP_SLAVE_THREADS], &slave_threads, 10);
++    if (err) return err;
++
++    int rcode = 0;
++
++    if (slave_threads > 1)
++        /* Need to check AUTOINC_LOCK_MODE and LOCKS_UNSAFE_FOR_BINLOG */
++    {
++        long long autoinc_lock_mode;
++        err = get_long_long (opts[AUTOINC_LOCK_MODE], &autoinc_lock_mode, 10);
++        if (err) return err;
++
++        bool locks_unsafe_for_binlog;
++        err = get_bool (opts[LOCKS_UNSAFE_FOR_BINLOG],&locks_unsafe_for_binlog);
++        if (err) return err;
++
++        if (autoinc_lock_mode != 2)
++        {
++            WSREP_ERROR ("Parallel applying (wsrep_slave_threads > 1) requires"
++                         " innodb_autoinc_lock_mode = 2.");
++            rcode = EINVAL;
++        }
++    }
++
++    bool locked_in_memory;
++    err = get_bool (opts[LOCKED_IN_MEMORY], &locked_in_memory);
++    if (err) { WSREP_ERROR("get_bool error: %s", strerror(err)); return err; }
++    if (locked_in_memory)
++    {
++        WSREP_ERROR ("Memory locking is not supported (locked_in_memory=%s)",
++                     locked_in_memory ? "ON" : "OFF");
++        rcode = EINVAL;
++    }
++
++    if (!strcasecmp(opts[WSREP_SST_METHOD].value,"mysqldump"))
++    {
++        if (!strcasecmp(opts[BIND_ADDRESS].value, "127.0.0.1") ||
++            !strcasecmp(opts[BIND_ADDRESS].value, "localhost"))
++        {
++            WSREP_ERROR ("wsrep_sst_method is set to 'mysqldump' yet "
++                         "mysqld bind_address is set to '%s', which makes it "
++                         "impossible to receive state transfer from another "
++                         "node, since mysqld won't accept such connections. "
++                         "If you wish to use mysqldump state transfer method, "
++                         "set bind_address to allow mysql client connections "
++                         "from other cluster members (e.g. 0.0.0.0).",
++                         opts[BIND_ADDRESS].value);
++            rcode = EINVAL;
++        }
++    }
++    else
++    {
++        // non-mysqldump SST requires wsrep_cluster_address on startup
++        if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0)
++        {
++            WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be "
++                         "configured on startup.",opts[WSREP_SST_METHOD].value);
++            rcode = EINVAL;
++        }
++    }
++
++    if (strcasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, "AUTO"))
++    {
++        if (!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value,
++                         "127.0.0.1", strlen("127.0.0.1"))       ||
++            !strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value,
++                         "localhost", strlen("localhost")))
++        {
++            WSREP_WARN  ("wsrep_sst_receive_address is set to '%s' which "
++                         "makes it impossible for another host to reach this "
++                         "one. Please set it to the address which this node "
++                         "can be connected at by other cluster members.",
++                         opts[WSREP_SST_RECEIVE_ADDRESS].value);
++//            rcode = EINVAL;
++        }
++    }
++
++    if (strcasecmp(opts[WSREP_PROVIDER].value, "none"))
++    {
++        if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW"))
++        {
++            WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. "
++                         "Configured value: '%s'. Please adjust your "
++                         "configuration.", opts[BINLOG_FORMAT].value);
++
++            rcode = EINVAL;
++        }
++    }
++
++    return rcode;
++}
++
++int
++wsrep_check_opts (int const argc, char* const* const argv)
++{
++    return check_opts (argc, argv, opts);
++}
++
+diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
+new file mode 100644
+index 0000000..e89858c
+--- /dev/null
++++ b/sql/wsrep_hton.cc
+@@ -0,0 +1,590 @@
++/* Copyright 2008 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#include <mysqld.h>
++#include "sql_base.h"
++#include "binlog.h"
++#include "rpl_filter.h"
++#include <sql_class.h>
++#include "wsrep_mysqld.h"
++#include "wsrep_binlog.h"
++#include <cstdio>
++#include <cstdlib>
++
++extern ulonglong thd_to_trx_id(THD *thd);
++
++extern "C" int thd_binlog_format(const MYSQL_THD thd);
++// todo: share interface with ha_innodb.c
++
++enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton,
++                                             bool all);
++
++/*
++  Cleanup after local transaction commit/rollback, replay or TOI.
++*/
++void wsrep_cleanup_transaction(THD *thd)
++{
++  if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd);
++  thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
++  thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
++  thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
++  thd->wsrep_exec_mode= LOCAL_STATE;
++  return;
++}
++
++/*
++  wsrep hton
++*/
++handlerton *wsrep_hton;
++
++
++/*
++  Registers wsrep hton at commit time if transaction has registered htons
++  for supported engine types.
++
++  Hton should not be registered for TOTAL_ORDER operations.
++
++  Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run
++  commit in 2pc so that wsrep position gets properly recorded in storage
++  engines.
++
++  Note that all hton calls should immediately return for threads that are
++  in REPL_RECV mode as their states are controlled by wsrep appliers or
++  replaying code. Only threads in LOCAL_MODE should run wsrep callbacks
++  from hton methods.
++*/
++void wsrep_register_hton(THD* thd, bool all)
++{
++  if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi)
++  {
++    THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
++    for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next())
++    {
++      if (i->ht()->db_type == DB_TYPE_INNODB)
++      {
++        trans_register_ha(thd, all, wsrep_hton);
++
++        /* follow innodb read/write settting
++         * but, as an exception: CTAS with empty result set will not be
++         * replicated unless we declare wsrep hton as read/write here
++       */
++        if (i->is_trx_read_write() ||
++            (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
++             thd->wsrep_exec_mode == LOCAL_STATE))
++        {
++          thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write();
++        }
++        break;
++      }
++    }
++  }
++}
++
++/*
++  Calls wsrep->post_commit() for locally executed transactions that have
++  got seqno from provider (must commit) and don't require replaying.
++ */
++void wsrep_post_commit(THD* thd, bool all)
++{
++  switch (thd->wsrep_exec_mode)
++  {
++  case LOCAL_COMMIT:
++    {
++      DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
++      if (wsrep->post_commit(wsrep, &thd->wsrep_ws_handle))
++      {
++        DBUG_PRINT("wsrep", ("set committed fail"));
++        WSREP_WARN("set committed fail: %llu %d",
++                   (long long)thd->real_id, thd->get_stmt_da()->status());
++      }
++      wsrep_cleanup_transaction(thd);
++      break;
++    }
++ case LOCAL_STATE:
++   {
++     /* non-InnoDB statements may have populated events in stmt cache 
++      => cleanup 
++     */
++     WSREP_DEBUG("cleanup transaction for LOCAL_STATE: %s", thd->query());
++     wsrep_cleanup_transaction(thd);
++     break;
++   }
++  default: break;
++  }
++
++}
++
++/*
++  wsrep exploits binlog's caches even if binlogging itself is not
++  activated. In such case connection close needs calling
++  actual binlog's method.
++  Todo: split binlog hton from its caches to use ones by wsrep
++  without referring to binlog's stuff.
++*/
++static int
++wsrep_close_connection(handlerton*  hton, THD* thd)
++{
++  DBUG_ENTER("wsrep_close_connection");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++  DBUG_RETURN(wsrep_binlog_close_connection (thd));
++}
++
++/*
++  prepare/wsrep_run_wsrep_commit can fail in two ways
++  - certification test or an equivalent. As a result,
++    the current transaction just rolls back
++    Error codes:
++           WSREP_TRX_CERT_FAIL, WSREP_TRX_SIZE_EXCEEDED, WSREP_TRX_ERROR
++  - a post-certification failure makes this server unable to
++    commit its own WS and therefore the server must abort
++*/
++static int wsrep_prepare(handlerton *hton, THD *thd, bool all)
++{
++  DBUG_ENTER("wsrep_prepare");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++
++  DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
++  DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
++  DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
++
++  if ((all ||
++      !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
++      (thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd)))
++  {
++    DBUG_RETURN (wsrep_run_wsrep_commit(thd, hton, all));
++  }
++  DBUG_RETURN(0);
++}
++
++static int wsrep_savepoint_set(handlerton *hton, THD *thd,  void *sv)
++{
++  DBUG_ENTER("wsrep_savepoint_set");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++
++  if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
++  int rcode = wsrep_binlog_savepoint_set(thd, sv);
++  DBUG_RETURN(rcode);
++}
++
++static int wsrep_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
++{
++  DBUG_ENTER("wsrep_savepoint_rollback");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++
++  if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
++  int rcode = wsrep_binlog_savepoint_rollback(thd, sv);
++  DBUG_RETURN(rcode);
++}
++
++static int wsrep_rollback(handlerton *hton, THD *thd, bool all)
++{
++  DBUG_ENTER("wsrep_rollback");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  switch (thd->wsrep_exec_mode)
++  {
++  case TOTAL_ORDER:
++  case REPL_RECV:
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++      WSREP_DEBUG("Avoiding wsrep rollback for failed DDL: %s", thd->query());
++      DBUG_RETURN(0);
++  default: break;
++  }
++
++  if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
++      (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
++  {
++    if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
++    {
++      DBUG_PRINT("wsrep", ("setting rollback fail"));
++      WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
++                  (long long)thd->real_id, thd->query());
++    }
++    wsrep_cleanup_transaction(thd);
++  }
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  DBUG_RETURN(0);
++}
++
++int wsrep_commit(handlerton *hton, THD *thd, bool all)
++{
++  DBUG_ENTER("wsrep_commit");
++
++  if (thd->wsrep_exec_mode == REPL_RECV)
++  {
++    DBUG_RETURN(0);
++  }
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
++      (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
++  {
++    if (thd->wsrep_exec_mode == LOCAL_COMMIT)
++    {
++      DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
++      /*
++        Call to wsrep->post_commit() (moved to wsrep_post_commit()) must
++        be done only after commit has done for all involved htons.
++      */
++      DBUG_PRINT("wsrep", ("commit"));
++    }
++    else
++    {
++      /*
++        Transaction didn't go through wsrep->pre_commit() so just roll back
++        possible changes to clean state.
++      */
++      if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
++      {
++        DBUG_PRINT("wsrep", ("setting rollback fail"));
++        WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
++                    (long long)thd->real_id, thd->query());
++      }
++      wsrep_cleanup_transaction(thd);
++    }
++  }
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  DBUG_RETURN(0);
++}
++
++
++extern Rpl_filter* binlog_filter;
++extern my_bool opt_log_slave_updates;
++
++enum wsrep_trx_status
++wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
++{
++  int rcode= -1;
++  size_t data_len= 0;
++  IO_CACHE *cache;
++  int replay_round= 0;
++
++  if (thd->get_stmt_da()->is_error()) {
++    WSREP_ERROR("commit issue, error: %d %s",
++                thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
++  }
++
++  DBUG_ENTER("wsrep_run_wsrep_commit");
++
++  if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
++
++  if (thd->wsrep_exec_mode == REPL_RECV) {
++
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    if (thd->wsrep_conflict_state == MUST_ABORT) {
++      if (wsrep_debug)
++        WSREP_INFO("WSREP: must abort for BF");
++      DBUG_PRINT("wsrep", ("BF apply commit fail"));
++      thd->wsrep_conflict_state = NO_CONFLICT;
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++      //
++      // TODO: test all calls of the rollback.
++      // rollback must happen automagically innobase_rollback(hton, thd, 1);
++      //
++      DBUG_RETURN(WSREP_TRX_ERROR);
++    }
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++
++  if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK);
++
++  if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) {
++    WSREP_DEBUG("commit for consistency check: %s", thd->query());
++    DBUG_RETURN(WSREP_TRX_OK);
++  }
++
++  DBUG_PRINT("wsrep", ("replicating commit"));
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  if (thd->wsrep_conflict_state == MUST_ABORT) {
++    DBUG_PRINT("wsrep", ("replicate commit fail"));
++    thd->wsrep_conflict_state = ABORTED;
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    if (wsrep_debug) {
++      WSREP_INFO("innobase_commit, abort %s",
++                 (thd->query()) ? thd->query() : "void");
++    }
++    DBUG_RETURN(WSREP_TRX_CERT_FAIL);
++  }
++
++  mysql_mutex_lock(&LOCK_wsrep_replaying);
++
++  while (wsrep_replaying > 0                       &&
++         thd->wsrep_conflict_state == NO_CONFLICT  &&
++         thd->killed == THD::NOT_KILLED            &&
++         !shutdown_in_progress)
++  {
++
++    mysql_mutex_unlock(&LOCK_wsrep_replaying);
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++    mysql_mutex_lock(&thd->mysys_var->mutex);
++    thd_proc_info(thd, "wsrep waiting on replaying");
++    thd->mysys_var->current_mutex= &LOCK_wsrep_replaying;
++    thd->mysys_var->current_cond=  &COND_wsrep_replaying;
++    mysql_mutex_unlock(&thd->mysys_var->mutex);
++
++    mysql_mutex_lock(&LOCK_wsrep_replaying);
++    // Using timedwait is a hack to avoid deadlock in case if BF victim
++    // misses the signal.
++    struct timespec wtime = {0, 1000000};
++    mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying,
++                       &wtime);
++
++    if (replay_round++ % 100000 == 0)
++      WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lu) "
++                  "conflict: %d (round: %d)",
++                wsrep_replaying, thd->thread_id,
++                  thd->wsrep_conflict_state, replay_round);
++
++    mysql_mutex_unlock(&LOCK_wsrep_replaying);
++
++    mysql_mutex_lock(&thd->mysys_var->mutex);
++    thd->mysys_var->current_mutex= 0;
++    thd->mysys_var->current_cond=  0;
++    mysql_mutex_unlock(&thd->mysys_var->mutex);
++
++    mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    mysql_mutex_lock(&LOCK_wsrep_replaying);
++  }
++  mysql_mutex_unlock(&LOCK_wsrep_replaying);
++
++  if (thd->wsrep_conflict_state == MUST_ABORT) {
++    DBUG_PRINT("wsrep", ("replicate commit fail"));
++    thd->wsrep_conflict_state = ABORTED;
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    WSREP_DEBUG("innobase_commit abort after replaying wait %s",
++                (thd->query()) ? thd->query() : "void");
++    DBUG_RETURN(WSREP_TRX_CERT_FAIL);
++  }
++
++  thd->wsrep_query_state = QUERY_COMMITTING;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  cache = get_trans_log(thd);
++  rcode = 0;
++  if (cache) {
++    thd->binlog_flush_pending_rows_event(true);
++    rcode = wsrep_write_cache(wsrep, thd, cache, &data_len);
++    if (WSREP_OK != rcode) {
++      WSREP_ERROR("rbr write fail, data_len: %zu, %d", data_len, rcode);
++      DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
++    }
++  }
++
++  if (data_len == 0)
++  {
++    if (thd->get_stmt_da()->is_ok()              &&
++        thd->get_stmt_da()->affected_rows() > 0  &&
++        !binlog_filter->is_on())
++    {
++      WSREP_DEBUG("empty rbr buffer, query: %s, "
++                 "affected rows: %llu, "
++                 "changed tables: %d, "
++                 "sql_log_bin: %d, "
++                 "wsrep status (%d %d %d)",
++                 thd->query(), thd->get_stmt_da()->affected_rows(),
++                 stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin,
++                 thd->wsrep_exec_mode, thd->wsrep_query_state,
++                 thd->wsrep_conflict_state);
++    }
++    else
++    {
++      WSREP_DEBUG("empty rbr buffer, query: %s", thd->query());
++    }
++    thd->wsrep_query_state= QUERY_EXEC;
++    DBUG_RETURN(WSREP_TRX_OK);
++  }
++
++  if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id)
++  {
++    WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %zu\n"
++             "QUERY: %s\n"
++             " => Skipping replication",
++             thd->thread_id, data_len, thd->query());
++    rcode = WSREP_TRX_FAIL;
++  }
++  else if (!rcode)
++  {
++    if (WSREP_OK == rcode)
++      rcode = wsrep->pre_commit(wsrep,
++                                (wsrep_conn_id_t)thd->thread_id,
++                                &thd->wsrep_ws_handle,
++                                WSREP_FLAG_COMMIT |
++                                ((thd->wsrep_PA_safe) ?
++                                 0ULL : WSREP_FLAG_PA_UNSAFE),
++                                &thd->wsrep_trx_meta);
++
++    if (rcode == WSREP_TRX_MISSING) {
++      WSREP_WARN("Transaction missing in provider, thd: %ld, SQL: %s",
++                 thd->thread_id, thd->query());
++      rcode = WSREP_TRX_FAIL;
++    } else if (rcode == WSREP_BF_ABORT) {
++      WSREP_DEBUG("thd %lu seqno %lld BF aborted by provider, will replay",
++                  thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno);
++      mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++      thd->wsrep_conflict_state = MUST_REPLAY;
++      DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++      mysql_mutex_lock(&LOCK_wsrep_replaying);
++      wsrep_replaying++;
++      WSREP_DEBUG("replaying increased: %d, thd: %lu",
++                  wsrep_replaying, thd->thread_id);
++      mysql_mutex_unlock(&LOCK_wsrep_replaying);
++    }
++  } else {
++    WSREP_ERROR("I/O error reading from thd's binlog iocache: "
++                "errno=%d, io cache code=%d", my_errno, cache->error);
++    DBUG_ASSERT(0); // failure like this can not normally happen
++    DBUG_RETURN(WSREP_TRX_ERROR);
++  }
++
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  switch(rcode) {
++  case 0:
++    /*
++      About MUST_ABORT: We assume that even if thd conflict state was set
++      to MUST_ABORT, underlying transaction was not rolled back or marked
++      as deadlock victim in QUERY_COMMITTING state. Conflict state is
++      set to NO_CONFLICT and commit proceeds as usual.
++    */
++    if (thd->wsrep_conflict_state == MUST_ABORT)
++        thd->wsrep_conflict_state= NO_CONFLICT;
++
++    if (thd->wsrep_conflict_state != NO_CONFLICT)
++    {
++      WSREP_WARN("thd %lu seqno %lld: conflict state %d after post commit",
++                 thd->thread_id,
++                 (long long)thd->wsrep_trx_meta.gtid.seqno,
++                 thd->wsrep_conflict_state);
++    }
++    thd->wsrep_exec_mode= LOCAL_COMMIT;
++    DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
++    /* Override XID iff it was generated by mysql */
++    if (thd->transaction.xid_state.xid.get_my_xid())
++    {
++      wsrep_xid_init(&thd->transaction.xid_state.xid,
++                     &thd->wsrep_trx_meta.gtid.uuid,
++                     thd->wsrep_trx_meta.gtid.seqno);
++    }
++    DBUG_PRINT("wsrep", ("replicating commit success"));
++    break;
++  case WSREP_BF_ABORT:
++    DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
++  case WSREP_TRX_FAIL:
++    WSREP_DEBUG("commit failed for reason: %d %lu %s", rcode, thd->thread_id, thd->query());
++    DBUG_PRINT("wsrep", ("replicating commit fail"));
++
++    thd->wsrep_query_state= QUERY_EXEC;
++
++    if (thd->wsrep_conflict_state == MUST_ABORT) {
++      thd->wsrep_conflict_state= ABORTED;
++    }
++    else
++    {
++      WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state);
++      if (thd->wsrep_conflict_state == NO_CONFLICT)
++      {
++        thd->wsrep_conflict_state = CERT_FAILURE;
++        WSREP_LOG_CONFLICT(NULL, thd, FALSE);
++      }
++    }
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++    DBUG_RETURN(WSREP_TRX_CERT_FAIL);
++
++  case WSREP_SIZE_EXCEEDED:
++    WSREP_ERROR("transaction size exceeded");
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
++  case WSREP_CONN_FAIL:
++    WSREP_ERROR("connection failure");
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    DBUG_RETURN(WSREP_TRX_ERROR);
++  default:
++    WSREP_ERROR("unknown connection failure");
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    DBUG_RETURN(WSREP_TRX_ERROR);
++  }
++
++  thd->wsrep_query_state= QUERY_EXEC;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  DBUG_RETURN(WSREP_TRX_OK);
++}
++
++
++static int wsrep_hton_init(void *p)
++{
++  wsrep_hton= (handlerton *)p;
++  //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
++  wsrep_hton->state= SHOW_OPTION_YES;
++  wsrep_hton->db_type=DB_TYPE_WSREP;
++  wsrep_hton->savepoint_offset= sizeof(my_off_t);
++  wsrep_hton->close_connection= wsrep_close_connection;
++  wsrep_hton->savepoint_set= wsrep_savepoint_set;
++  wsrep_hton->savepoint_rollback= wsrep_savepoint_rollback;
++  wsrep_hton->commit= wsrep_commit;
++  wsrep_hton->rollback= wsrep_rollback;
++  wsrep_hton->prepare= wsrep_prepare;
++  wsrep_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; // todo: fix flags
++  wsrep_hton->slot= 0;
++  return 0;
++}
++
++
++struct st_mysql_storage_engine wsrep_storage_engine=
++{ MYSQL_HANDLERTON_INTERFACE_VERSION };
++
++
++mysql_declare_plugin(wsrep)
++{
++  MYSQL_STORAGE_ENGINE_PLUGIN,
++  &wsrep_storage_engine,
++  "wsrep",
++  "Codership Oy",
++  "A pseudo storage engine to represent transactions in multi-master "
++  "synchornous replication",
++  PLUGIN_LICENSE_GPL,
++  wsrep_hton_init, /* Plugin Init */
++  NULL, /* Plugin Deinit */
++  0x0100 /* 1.0 */,
++  NULL,                       /* status variables                */
++  NULL,                       /* system variables                */
++  NULL,                       /* config options                  */
++  0,                          /* flags                           */
++}
++mysql_declare_plugin_end;
+diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
+new file mode 100644
+index 0000000..e2816c4
+--- /dev/null
++++ b/sql/wsrep_mysqld.cc
+@@ -0,0 +1,1564 @@
++/* Copyright 2008-2013 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#include <mysqld.h>
++#include <sql_class.h>
++#include <sql_parse.h>
++#include "wsrep_priv.h"
++#include "wsrep_thd.h"
++#include "wsrep_sst.h"
++#include "wsrep_utils.h"
++#include "wsrep_var.h"
++#include "wsrep_binlog.h"
++#include "wsrep_applier.h"
++#include <cstdio>
++#include <cstdlib>
++#include "log_event.h"
++#include <rpl_slave.h>
++
++wsrep_t *wsrep                  = NULL;
++my_bool wsrep_emulate_bin_log   = FALSE; // activating parts of binlog interface
++/* Sidno in global_sid_map corresponding to group uuid */
++rpl_sidno wsrep_sidno= -1;
++my_bool wsrep_preordered_opt= FALSE;
++
++/*
++ * Begin configuration options and their default values
++ */
++
++const char* wsrep_data_home_dir = NULL;
++const char* wsrep_dbug_option   = "";
++
++long    wsrep_slave_threads            = 1; // # of slave action appliers wanted
++int     wsrep_slave_count_change       = 0; // # of appliers to stop or start
++my_bool wsrep_debug                    = 0; // enable debug level logging
++my_bool wsrep_convert_LOCK_to_trx      = 1; // convert locking sessions to trx
++ulong   wsrep_retry_autocommit         = 5; // retry aborted autocommit trx
++my_bool wsrep_auto_increment_control   = 1; // control auto increment variables
++my_bool wsrep_drupal_282555_workaround = 1; // retry autoinc insert after dupkey
++my_bool wsrep_incremental_data_collection = 0; // incremental data collection
++ulong   wsrep_max_ws_size              = 1073741824UL;//max ws (RBR buffer) size
++ulong   wsrep_max_ws_rows              = 65536; // max number of rows in ws
++int     wsrep_to_isolation             = 0; // # of active TO isolation threads
++my_bool wsrep_certify_nonPK            = 1; // certify, even when no primary key
++long    wsrep_max_protocol_version     = 3; // maximum protocol version to use
++ulong   wsrep_forced_binlog_format     = BINLOG_FORMAT_UNSPEC;
++my_bool wsrep_recovery                 = 0; // recovery
++my_bool wsrep_replicate_myisam         = 0; // enable myisam replication
++my_bool wsrep_log_conflicts            = 0;
++ulong   wsrep_mysql_replication_bundle = 0;
++my_bool wsrep_desync                   = 0; // desynchronize the node from the
++                                            // cluster
++my_bool wsrep_load_data_splitting      = 1; // commit load data every 10K intervals
++my_bool wsrep_restart_slave            = 0; // should mysql slave thread be
++                                            // restarted, if node joins back
++my_bool wsrep_restart_slave_activated  = 0; // node has dropped, and slave
++                                            // restart will be needed
++my_bool wsrep_slave_UK_checks          = 0; // slave thread does UK checks
++my_bool wsrep_slave_FK_checks          = 0; // slave thread does FK checks
++/*
++ * End configuration options
++ */
++
++static const wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED;
++static char         cluster_uuid_str[40]= { 0, };
++static const char*  cluster_status_str[WSREP_VIEW_MAX] =
++{
++    "Primary",
++    "non-Primary",
++    "Disconnected"
++};
++
++static char provider_name[256]= { 0, };
++static char provider_version[256]= { 0, };
++static char provider_vendor[256]= { 0, };
++
++/*
++ * wsrep status variables
++ */
++my_bool     wsrep_connected          = FALSE;
++my_bool     wsrep_ready              = FALSE; // node can accept queries
++const char* wsrep_cluster_state_uuid = cluster_uuid_str;
++long long   wsrep_cluster_conf_id    = WSREP_SEQNO_UNDEFINED;
++const char* wsrep_cluster_status = cluster_status_str[WSREP_VIEW_DISCONNECTED];
++long        wsrep_cluster_size       = 0;
++long        wsrep_local_index        = -1;
++long long   wsrep_local_bf_aborts    = 0;
++const char* wsrep_provider_name      = provider_name;
++const char* wsrep_provider_version   = provider_version;
++const char* wsrep_provider_vendor    = provider_vendor;
++/* End wsrep status variables */
++
++wsrep_uuid_t     local_uuid   = WSREP_UUID_UNDEFINED;
++wsrep_seqno_t    local_seqno  = WSREP_SEQNO_UNDEFINED;
++wsp::node_status local_status;
++long             wsrep_protocol_version = 3;
++
++// Boolean denoting if server is in initial startup phase. This is needed
++// to make sure that main thread waiting in wsrep_sst_wait() is signaled
++// if there was no state gap on receiving first view event.
++static my_bool   wsrep_startup = TRUE;
++
++
++static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) {
++  switch (level) {
++  case WSREP_LOG_INFO:
++    sql_print_information("WSREP: %s", msg);
++    break;
++  case WSREP_LOG_WARN:
++    sql_print_warning("WSREP: %s", msg);
++    break;
++  case WSREP_LOG_ERROR:
++  case WSREP_LOG_FATAL:
++    sql_print_error("WSREP: %s", msg);
++    break;
++  case WSREP_LOG_DEBUG:
++    if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
++  default:
++    break;
++  }
++}
++
++static void wsrep_log_states (wsrep_log_level_t   const level,
++                              const wsrep_uuid_t* const group_uuid,
++                              wsrep_seqno_t       const group_seqno,
++                              const wsrep_uuid_t* const node_uuid,
++                              wsrep_seqno_t       const node_seqno)
++{
++  char uuid_str[37];
++  char msg[256];
++
++  wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str));
++  snprintf (msg, 255, "WSREP: Group state: %s:%lld",
++            uuid_str, (long long)group_seqno);
++  wsrep_log_cb (level, msg);
++
++  wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str));
++  snprintf (msg, 255, "WSREP: Local state: %s:%lld",
++            uuid_str, (long long)node_seqno);
++  wsrep_log_cb (level, msg);
++}
++
++static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
++{
++  XID* xid= reinterpret_cast<XID*>(arg);
++  handlerton* hton= plugin_data(plugin, handlerton *);
++  if (hton->db_type == DB_TYPE_INNODB)
++  {
++    const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid));
++    char uuid_str[40] = {0, };
++    wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
++    WSREP_DEBUG("Set WSREPXid for InnoDB:  %s:%lld",
++                uuid_str, (long long)wsrep_xid_seqno(xid));
++    hton->wsrep_set_checkpoint(hton, xid);
++  }
++  return FALSE;
++}
++
++void wsrep_set_SE_checkpoint(XID* xid)
++{
++  plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid);
++}
++
++static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
++{
++  XID* xid= reinterpret_cast<XID*>(arg);
++  handlerton* hton= plugin_data(plugin, handlerton *);
++  if (hton->db_type == DB_TYPE_INNODB)
++  {
++    hton->wsrep_get_checkpoint(hton, xid);
++    const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid));
++    char uuid_str[40] = {0, };
++    wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
++    WSREP_DEBUG("Read WSREPXid from InnoDB:  %s:%lld",
++                uuid_str, (long long)wsrep_xid_seqno(xid));
++
++  }
++  return FALSE;
++}
++
++void wsrep_get_SE_checkpoint(XID* xid)
++{
++  plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid);
++}
++
++void wsrep_init_sidno(const wsrep_uuid_t& uuid)
++{
++  /* generate new Sid map entry from inverted uuid */
++  rpl_sid sid;
++  wsrep_uuid_t ltid_uuid;
++  for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i)
++  {
++      ltid_uuid.data[i] = ~local_uuid.data[i];
++  }
++  sid.copy_from(ltid_uuid.data);
++  global_sid_lock->wrlock();
++  wsrep_sidno= global_sid_map->add_sid(sid);
++  WSREP_INFO("inited wsrep sidno %d", wsrep_sidno);
++  global_sid_lock->unlock();
++}
++
++
++static wsrep_cb_status_t
++wsrep_view_handler_cb (void*                    app_ctx,
++                       void*                    recv_ctx,
++                       const wsrep_view_info_t* view,
++                       const char*              state,
++                       size_t                   state_len,
++                       void**                   sst_req,
++                       size_t*                  sst_req_len)
++{
++  *sst_req     = NULL;
++  *sst_req_len = 0;
++
++  wsrep_member_status_t new_status= local_status.get();
++
++  if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t)))
++  {
++    memcpy((wsrep_uuid_t*)&cluster_uuid, &view->state_id.uuid,
++           sizeof(cluster_uuid));
++
++    wsrep_uuid_print (&cluster_uuid, cluster_uuid_str,
++                      sizeof(cluster_uuid_str));
++  }
++
++  wsrep_cluster_conf_id= view->view;
++  wsrep_cluster_status= cluster_status_str[view->status];
++  wsrep_cluster_size= view->memb_num;
++  wsrep_local_index= view->my_idx;
++
++  WSREP_INFO("New cluster view: global state: %s:%lld, view# %lld: %s, "
++             "number of nodes: %ld, my index: %ld, protocol version %d",
++             wsrep_cluster_state_uuid, (long long)view->state_id.seqno,
++             (long long)wsrep_cluster_conf_id, wsrep_cluster_status,
++             wsrep_cluster_size, wsrep_local_index, view->proto_ver);
++
++  /* Proceed further only if view is PRIMARY */
++  if (WSREP_VIEW_PRIMARY != view->status) {
++    wsrep_ready_set(FALSE);
++    new_status= WSREP_MEMBER_UNDEFINED;
++    /* Always record local_uuid and local_seqno in non-prim since this
++     * may lead to re-initializing provider and start position is
++     * determined according to these variables */
++    // WRONG! local_uuid should be the last primary configuration uuid we were
++    // a member of. local_seqno should be updated in commit calls.
++    // local_uuid= cluster_uuid;
++    // local_seqno= view->first - 1;
++    goto out;
++  }
++
++  switch (view->proto_ver)
++  {
++  case 0:
++  case 1:
++  case 2:
++  case 3:
++      // version change
++      if (view->proto_ver != wsrep_protocol_version)
++      {
++          my_bool wsrep_ready_saved= wsrep_ready;
++          wsrep_ready_set(FALSE);
++          WSREP_INFO("closing client connections for "
++                     "protocol change %ld -> %d",
++                     wsrep_protocol_version, view->proto_ver);
++          wsrep_close_client_connections(TRUE);
++          wsrep_protocol_version= view->proto_ver;
++          wsrep_ready_set(wsrep_ready_saved);
++      }
++      break;
++  default:
++      WSREP_ERROR("Unsupported application protocol version: %d",
++                  view->proto_ver);
++      unireg_abort(1);
++  }
++
++  if (view->state_gap)
++  {
++    WSREP_WARN("Gap in state sequence. Need state transfer.");
++
++    /* After that wsrep will call wsrep_sst_prepare. */
++    /* keep ready flag 0 until we receive the snapshot */
++    wsrep_ready_set(FALSE);
++
++    /* Close client connections to ensure that they don't interfere
++     * with SST. Necessary only if storage engines are initialized
++     * before SST.
++     * TODO: Just killing all ongoing transactions should be enough
++     * since wsrep_ready is OFF and no new transactions can start.
++     */
++    if (!wsrep_before_SE())
++    {
++        WSREP_DEBUG("[debug]: closing client connections for PRIM");
++        wsrep_close_client_connections(TRUE);
++    }
++
++    ssize_t const req_len= wsrep_sst_prepare (sst_req);
++
++    if (req_len < 0)
++    {
++      WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
++                  strerror(-req_len));
++      new_status= WSREP_MEMBER_UNDEFINED;
++    }
++    else
++    {
++      assert(sst_req != NULL);
++      *sst_req_len= req_len;
++      new_status= WSREP_MEMBER_JOINER;
++    }
++  }
++  else
++  {
++    /*
++     *  NOTE: Initialize wsrep_group_uuid here only if it wasn't initialized
++     *  before - OR - it was reinitilized on startup (lp:992840)
++     */
++    if (wsrep_startup)
++    {
++      if (wsrep_before_SE())
++      {
++        wsrep_SE_init_grab();
++        // Signal mysqld init thread to continue
++        wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false);
++        // and wait for SE initialization
++        wsrep_SE_init_wait();
++      }
++      else
++      {
++        local_uuid=  cluster_uuid;
++        local_seqno= view->state_id.seqno;
++      }
++      /* Init storage engine XIDs from first view */
++      XID xid;
++      wsrep_xid_init(&xid, &local_uuid, local_seqno);
++      wsrep_set_SE_checkpoint(&xid);
++      new_status= WSREP_MEMBER_JOINED;
++      wsrep_init_sidno(local_uuid);
++    }
++
++    // just some sanity check
++    if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t)))
++    {
++      WSREP_ERROR("Undetected state gap. Can't continue.");
++      wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno,
++                       &local_uuid, -1);
++      unireg_abort(1);
++    }
++  }
++
++  if (wsrep_auto_increment_control)
++  {
++    global_system_variables.auto_increment_offset= view->my_idx + 1;
++    global_system_variables.auto_increment_increment= view->memb_num;
++  }
++
++  { /* capabilities may be updated on new configuration */
++    uint64_t const caps(wsrep->capabilities (wsrep));
++
++    my_bool const idc((caps & WSREP_CAP_INCREMENTAL_WRITESET) != 0);
++    if (TRUE == wsrep_incremental_data_collection && FALSE == idc)
++    {
++      WSREP_WARN("Unsupported protocol downgrade: "
++                 "incremental data collection disabled. Expect abort.");
++    }
++    wsrep_incremental_data_collection = idc;
++  }
++
++out:
++  if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE;
++  local_status.set(new_status, view);
++
++  return WSREP_CB_SUCCESS;
++}
++
++void wsrep_ready_set (my_bool x)
++{
++  WSREP_DEBUG("Setting wsrep_ready to %d", x);
++  if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
++  if (wsrep_ready != x)
++  {
++    wsrep_ready= x;
++    mysql_cond_signal (&COND_wsrep_ready);
++  }
++  mysql_mutex_unlock (&LOCK_wsrep_ready);
++}
++
++// Wait until wsrep has reached ready state
++void wsrep_ready_wait ()
++{
++  if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
++  while (!wsrep_ready)
++  {
++    WSREP_INFO("Waiting to reach ready state");
++    mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready);
++  }
++  WSREP_INFO("ready state reached");
++  mysql_mutex_unlock (&LOCK_wsrep_ready);
++}
++
++static void wsrep_synced_cb(void* app_ctx)
++{
++  WSREP_INFO("Synchronized with group, ready for connections");
++  bool signal_main= false;
++  if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
++  if (!wsrep_ready)
++  {
++    wsrep_ready= TRUE;
++    mysql_cond_signal (&COND_wsrep_ready);
++    signal_main= true;
++
++  }
++  local_status.set(WSREP_MEMBER_SYNCED);
++  mysql_mutex_unlock (&LOCK_wsrep_ready);
++
++  if (signal_main)
++  {
++      wsrep_SE_init_grab();
++      // Signal mysqld init thread to continue
++      wsrep_sst_complete (&local_uuid, local_seqno, false);
++      // and wait for SE initialization
++      wsrep_SE_init_wait();
++  }
++  if (wsrep_restart_slave_activated)
++  {
++    int rcode;
++    WSREP_INFO("MySQL slave restart");
++    wsrep_restart_slave_activated= FALSE;
++
++    mysql_mutex_lock(&LOCK_active_mi);
++    if ((rcode = start_slave_threads(1 /* need mutex */,
++                            0 /* no wait for start*/,
++                            active_mi,
++                                  SLAVE_SQL)))
++    {
++      WSREP_WARN("Failed to create slave threads: %d", rcode);
++    }
++    mysql_mutex_unlock(&LOCK_active_mi);
++
++  }
++}
++
++static void wsrep_init_position()
++{
++  /* read XIDs from storage engines */
++  XID xid;
++  memset(&xid, 0, sizeof(xid));
++  xid.formatID= -1;
++  wsrep_get_SE_checkpoint(&xid);
++
++  if (xid.formatID == -1)
++  {
++    WSREP_INFO("Read nil XID from storage engines, skipping position init");
++    return;
++  }
++  else if (!wsrep_is_wsrep_xid(&xid))
++  {
++    WSREP_WARN("Read non-wsrep XID from storage engines, skipping position init");
++    return;
++  }
++
++  const wsrep_uuid_t* uuid= wsrep_xid_uuid(&xid);
++  const wsrep_seqno_t seqno= wsrep_xid_seqno(&xid);
++
++  char uuid_str[40] = {0, };
++  wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
++  WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno);
++
++
++  if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) &&
++      local_seqno == WSREP_SEQNO_UNDEFINED)
++  {
++    // Initial state
++    local_uuid= *uuid;
++    local_seqno= seqno;
++  }
++  else if (memcmp(&local_uuid, uuid, sizeof(local_uuid)) ||
++           local_seqno != seqno)
++  {
++    WSREP_WARN("Initial position was provided by configuration or SST, "
++               "avoiding override");
++  }
++}
++
++int wsrep_init()
++{
++  int rcode= -1;
++
++  wsrep_ready_set(FALSE);
++  assert(wsrep_provider);
++
++  wsrep_init_position();
++
++  if ((rcode= wsrep_load(wsrep_provider, &wsrep, wsrep_log_cb)) != WSREP_OK)
++  {
++    if (strcasecmp(wsrep_provider, WSREP_NONE))
++    {
++      WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.",
++                  wsrep_provider, strerror(rcode), rcode);
++      strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack
++      (void) wsrep_init();
++      return rcode;
++    }
++    else /* this is for recursive call above */
++    {
++      WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.",
++                  strerror(rcode), rcode);
++      unireg_abort(1);
++    }
++  }
++
++  if (strlen(wsrep_provider)== 0 ||
++      !strcmp(wsrep_provider, WSREP_NONE))
++  {
++    // enable normal operation in case no provider is specified
++    wsrep_ready_set(TRUE);
++    global_system_variables.wsrep_on = 0;
++    wsrep_init_args args;
++    args.logger_cb = wsrep_log_cb;
++    args.options = (wsrep_provider_options) ?
++            wsrep_provider_options : "";
++    rcode = wsrep->init(wsrep, &args);
++    if (rcode)
++    {
++      DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
++      WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
++      wsrep->free(wsrep);
++      free(wsrep);
++      wsrep = NULL;
++    }
++    return rcode;
++  }
++  else
++  {
++    global_system_variables.wsrep_on = 1;
++    strncpy(provider_name,
++            wsrep->provider_name,    sizeof(provider_name) - 1);
++    strncpy(provider_version,
++            wsrep->provider_version, sizeof(provider_version) - 1);
++    strncpy(provider_vendor,
++            wsrep->provider_vendor,  sizeof(provider_vendor) - 1);
++  }
++
++  if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
++    wsrep_data_home_dir = mysql_real_data_home;
++
++  char node_addr[512]= { 0, };
++  size_t const node_addr_max= sizeof(node_addr) - 1;
++  if (!wsrep_node_address || !strcmp(wsrep_node_address, ""))
++  {
++    size_t const ret= wsrep_guess_ip(node_addr, node_addr_max);
++    if (!(ret > 0 && ret < node_addr_max))
++    {
++      WSREP_WARN("Failed to guess base node address. Set it explicitly via "
++                 "wsrep_node_address.");
++      node_addr[0]= '\0';
++    }
++  }
++  else
++  {
++    strncpy(node_addr, wsrep_node_address, node_addr_max);
++  }
++
++  char inc_addr[512]= { 0, };
++  size_t const inc_addr_max= sizeof (inc_addr);
++  if ((!wsrep_node_incoming_address ||
++       !strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO)))
++  {
++    unsigned int my_bind_ip= INADDR_ANY; // default if not set
++    if (my_bind_addr_str && strlen(my_bind_addr_str))
++    {
++      my_bind_ip= wsrep_check_ip(my_bind_addr_str);
++    }
++
++    if (INADDR_ANY != my_bind_ip)
++    {
++      if (INADDR_NONE != my_bind_ip && INADDR_LOOPBACK != my_bind_ip)
++      {
++        snprintf(inc_addr, inc_addr_max, "%s:%u",
++                 my_bind_addr_str, (int)mysqld_port);
++      } // else leave inc_addr an empty string - mysqld is not listening for
++        // client connections on network interfaces.
++    }
++    else // mysqld binds to 0.0.0.0, take IP from wsrep_node_address if possible
++    {
++      size_t const node_addr_len= strlen(node_addr);
++      if (node_addr_len > 0)
++      {
++        const char* const colon= strrchr(node_addr, ':');
++        if (strchr(node_addr, ':') == colon) // 1 or 0 ':'
++        {
++          size_t const ip_len= colon ? colon - node_addr : node_addr_len;
++          if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
++          {
++            memcpy (inc_addr, node_addr, ip_len);
++            snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
++                     (int)mysqld_port);
++          }
++          else
++          {
++            WSREP_WARN("Guessing address for incoming client connections: "
++                       "address too long.");
++            inc_addr[0]= '\0';
++          }
++        }
++        else
++        {
++          WSREP_WARN("Guessing address for incoming client connections: "
++                     "too many colons :) .");
++          inc_addr[0]= '\0';
++        }
++      }
++
++      if (!strlen(inc_addr))
++      {
++          WSREP_WARN("Guessing address for incoming client connections failed. "
++                     "Try setting wsrep_node_incoming_address explicitly.");
++      }
++    }
++  }
++  else if (!strchr(wsrep_node_incoming_address, ':')) // no port included
++  {
++    if ((int)inc_addr_max <=
++        snprintf(inc_addr, inc_addr_max, "%s:%u",
++                 wsrep_node_incoming_address,(int)mysqld_port))
++    {
++      WSREP_WARN("Guessing address for incoming client connections: "
++                 "address too long.");
++      inc_addr[0]= '\0';
++    }
++  }
++  else
++  {
++    size_t const need = strlen (wsrep_node_incoming_address);
++    if (need >= inc_addr_max) {
++      WSREP_WARN("wsrep_node_incoming_address too long: %zu", need);
++      inc_addr[0]= '\0';
++    }
++    else {
++      memcpy (inc_addr, wsrep_node_incoming_address, need);
++    }
++  }
++
++  struct wsrep_init_args wsrep_args;
++
++  struct wsrep_gtid const state_id = { local_uuid, local_seqno };
++
++  wsrep_args.data_dir        = wsrep_data_home_dir;
++  wsrep_args.node_name       = (wsrep_node_name) ? wsrep_node_name : "";
++  wsrep_args.node_address    = node_addr;
++  wsrep_args.node_incoming   = inc_addr;
++  wsrep_args.options         = (wsrep_provider_options) ?
++                                wsrep_provider_options : "";
++  wsrep_args.proto_ver       = wsrep_max_protocol_version;
++
++  wsrep_args.state_id        = &state_id;
++
++  wsrep_args.logger_cb       = wsrep_log_cb;
++  wsrep_args.view_handler_cb = wsrep_view_handler_cb;
++  wsrep_args.apply_cb        = wsrep_apply_cb;
++  wsrep_args.commit_cb       = wsrep_commit_cb;
++  wsrep_args.unordered_cb    = wsrep_unordered_cb;
++  wsrep_args.sst_donate_cb   = wsrep_sst_donate_cb;
++  wsrep_args.synced_cb       = wsrep_synced_cb;
++
++  rcode = wsrep->init(wsrep, &wsrep_args);
++
++  if (rcode)
++  {
++    DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
++    WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
++    wsrep->free(wsrep);
++    free(wsrep);
++    wsrep = NULL;
++  }
++
++  return rcode;
++}
++
++extern int wsrep_on(void *);
++
++void wsrep_init_startup (bool first)
++{
++  if (wsrep_init()) unireg_abort(1);
++
++  wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd,
++                      wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on);
++
++  /* Skip replication start if no cluster address */
++  if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return;
++
++  if (first) wsrep_sst_grab(); // do it so we can wait for SST below
++
++  if (!wsrep_start_replication()) unireg_abort(1);
++
++  wsrep_create_rollbacker();
++  wsrep_create_appliers(1);
++
++  if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed
++}
++
++
++void wsrep_deinit()
++{
++  wsrep_unload(wsrep);
++  wsrep= 0;
++  provider_name[0]=    '\0';
++  provider_version[0]= '\0';
++  provider_vendor[0]=  '\0';
++}
++
++void wsrep_recover()
++{
++  if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)) &&
++      local_seqno == -2)
++  {
++    char uuid_str[40];
++    wsrep_uuid_print(&local_uuid, uuid_str, sizeof(uuid_str));
++    WSREP_INFO("Position %s:%lld given at startup, skipping position recovery",
++               uuid_str, (long long)local_seqno);
++    return;
++  }
++  XID xid;
++  memset(&xid, 0, sizeof(xid));
++  xid.formatID= -1;
++  wsrep_get_SE_checkpoint(&xid);
++  char uuid_str[40];
++  wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, sizeof(uuid_str));
++  WSREP_INFO("Recovered position: %s:%lld", uuid_str,
++             (long long)wsrep_xid_seqno(&xid));
++}
++
++
++void wsrep_stop_replication(THD *thd)
++{
++  WSREP_INFO("Stop replication");
++  if (!wsrep)
++  {
++    WSREP_INFO("Provider was not loaded, in stop replication");
++    return;
++  }
++
++  /* disconnect from group first to get wsrep_ready == FALSE */
++  WSREP_DEBUG("Provider disconnect");
++  wsrep->disconnect(wsrep);
++
++  wsrep_connected= FALSE;
++
++  wsrep_close_client_connections(TRUE);
++
++  /* wait until appliers have stopped */
++  wsrep_wait_appliers_close(thd);
++
++  return;
++}
++
++/* This one is set to true when --wsrep-new-cluster is found in the command
++ * line arguments */
++static my_bool wsrep_new_cluster= FALSE;
++#define WSREP_NEW_CLUSTER "--wsrep-new-cluster"
++/* Finds and hides --wsrep-new-cluster from the arguments list
++ * by moving it to the end of the list and decrementing argument count */
++void wsrep_filter_new_cluster (int* argc, char* argv[])
++{
++  int i;
++  for (i= *argc - 1; i > 0; i--)
++  {
++    /* make a copy of the argument to convert possible underscores to hyphens.
++     * the copy need not to be longer than WSREP_NEW_CLUSTER option */
++    char arg[sizeof(WSREP_NEW_CLUSTER) + 1]= { 0, };
++    strncpy(arg, argv[i], sizeof(arg) - 1);
++    char* underscore(arg);
++    while (NULL != (underscore= strchr(underscore, '_'))) *underscore= '-';
++
++    if (!strcmp(arg, WSREP_NEW_CLUSTER))
++    {
++      wsrep_new_cluster= TRUE;
++      *argc -= 1;
++      /* preserve the order of remaining arguments AND
++       * preserve the original argument pointers - just in case */
++      char* wnc= argv[i];
++      memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i]));
++      argv[*argc]= wnc; /* this will be invisible to the rest of the program */
++    }
++  }
++}
++
++bool wsrep_start_replication()
++{
++  wsrep_status_t rcode;
++
++  /*
++    if provider is trivial, don't even try to connect,
++    but resume local node operation
++  */
++  if (strlen(wsrep_provider)== 0 ||
++      !strcmp(wsrep_provider, WSREP_NONE))
++  {
++    // enable normal operation in case no provider is specified
++    wsrep_ready_set(TRUE);
++    return true;
++  }
++
++  if (!wsrep_cluster_address || strlen(wsrep_cluster_address)== 0)
++  {
++    // if provider is non-trivial, but no address is specified, wait for address
++    wsrep_ready_set(FALSE);
++    return true;
++  }
++
++  bool const bootstrap(TRUE == wsrep_new_cluster);
++  wsrep_new_cluster= FALSE;
++
++  WSREP_INFO("Start replication");
++
++  if ((rcode = wsrep->connect(wsrep,
++                              wsrep_cluster_name,
++                              wsrep_cluster_address,
++                              wsrep_sst_donor,
++                              bootstrap)))
++  {
++    if (-ESOCKTNOSUPPORT == rcode)
++    {
++      DBUG_PRINT("wsrep",("unrecognized cluster address: '%s', rcode: %d",
++                          wsrep_cluster_address, rcode));
++      WSREP_ERROR("unrecognized cluster address: '%s', rcode: %d",
++                  wsrep_cluster_address, rcode);
++    }
++    else
++    {
++      DBUG_PRINT("wsrep",("wsrep->connect() failed: %d", rcode));
++      WSREP_ERROR("wsrep::connect() failed: %d", rcode);
++    }
++
++    return false;
++  }
++  else
++  {
++    wsrep_connected= TRUE;
++
++    char* opts= wsrep->options_get(wsrep);
++    if (opts)
++    {
++      wsrep_provider_options_init(opts);
++      free(opts);
++    }
++    else
++    {
++      WSREP_WARN("Failed to get wsrep options");
++    }
++  }
++
++  return true;
++}
++
++bool wsrep_sync_wait (THD* thd, uint mask)
++{
++  if ((thd->variables.wsrep_sync_wait & mask) &&
++      thd->variables.wsrep_on &&
++      !thd->in_active_multi_stmt_transaction() &&
++      thd->wsrep_conflict_state != REPLAYING)
++  {
++    WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait = %u, mask = %u",
++                thd->variables.wsrep_sync_wait, mask);
++    // This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0
++    // TODO: modify to check if thd has locked any rows.
++    wsrep_gtid_t  gtid;
++    wsrep_status_t ret= wsrep->causal_read (wsrep, &gtid);
++
++    if (unlikely(WSREP_OK != ret))
++    {
++      const char* msg;
++      int err;
++
++      // Possibly relevant error codes:
++      // ER_CHECKREAD, ER_ERROR_ON_READ, ER_INVALID_DEFAULT, ER_EMPTY_QUERY,
++      // ER_FUNCTION_NOT_DEFINED, ER_NOT_ALLOWED_COMMAND, ER_NOT_SUPPORTED_YET,
++      // ER_FEATURE_DISABLED, ER_QUERY_INTERRUPTED
++
++      switch (ret)
++      {
++      case WSREP_NOT_IMPLEMENTED:
++        msg= "synchronous reads by wsrep backend. "
++             "Please unset wsrep_causal_reads variable.";
++        err= ER_NOT_SUPPORTED_YET;
++        break;
++      default:
++        msg= "Synchronous wait failed.";
++        err= ER_LOCK_WAIT_TIMEOUT; // NOTE: the above msg won't be displayed
++                                   //       with ER_LOCK_WAIT_TIMEOUT
++      }
++
++      my_error(err, MYF(0), msg);
++
++      return true;
++    }
++  }
++
++  return false;
++}
++
++/*
++ * Helpers to deal with TOI key arrays
++ */
++typedef struct wsrep_key_arr
++{
++    wsrep_key_t* keys;
++    size_t       keys_len;
++} wsrep_key_arr_t;
++
++
++static void wsrep_keys_free(wsrep_key_arr_t* key_arr)
++{
++    for (size_t i= 0; i < key_arr->keys_len; ++i)
++    {
++        my_free((void*)key_arr->keys[i].key_parts);
++    }
++    my_free(key_arr->keys);
++    key_arr->keys= 0;
++    key_arr->keys_len= 0;
++}
++
++
++/*!
++ * @param db      Database string
++ * @param table   Table string
++ * @param key     Array of wsrep_key_t
++ * @param key_len In: number of elements in key array, Out: number of
++ *                elements populated
++ *
++ * @return true if preparation was successful, otherwise false.
++ */
++
++static bool wsrep_prepare_key_for_isolation(const char* db,
++                                            const char* table,
++                                            wsrep_buf_t* key,
++                                            size_t* key_len)
++{
++    if (*key_len < 2) return false;
++
++    switch (wsrep_protocol_version)
++    {
++    case 0:
++        *key_len= 0;
++        break;
++    case 1:
++    case 2:
++    case 3:
++    {
++        *key_len= 0;
++        if (db)
++        {
++            // sql_print_information("%s.%s", db, table);
++            if (db)
++            {
++                key[*key_len].ptr= db;
++                key[*key_len].len= strlen(db);
++                ++(*key_len);
++                if (table)
++                {
++                    key[*key_len].ptr= table;
++                    key[*key_len].len= strlen(table);
++                    ++(*key_len);
++                }
++            }
++        }
++        break;
++    }
++    default:
++        return false;
++    }
++
++    return true;
++}
++
++/* Prepare key list from db/table and table_list */
++static bool wsrep_prepare_keys_for_isolation(THD*              thd,
++                                             const char*       db,
++                                             const char*       table,
++                                             const TABLE_LIST* table_list,
++                                             wsrep_key_arr_t*  ka)
++{
++    ka->keys= 0;
++    ka->keys_len= 0;
++
++    extern TABLE* find_temporary_table(THD*, const TABLE_LIST*);
++
++    if (db || table)
++    {
++        TABLE_LIST tmp_table;
++      MDL_request mdl_request;
++
++        memset(&tmp_table, 0, sizeof(tmp_table));
++        tmp_table.table_name= (char*)table;
++        tmp_table.db= (char*)db;
++      tmp_table.mdl_request.init(MDL_key::GLOBAL, (db) ? db :  "",
++                                 (table) ? table : "",
++                                 MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT);
++
++        if (!table || !find_temporary_table(thd, &tmp_table))
++        {
++            if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
++            {
++                WSREP_ERROR("Can't allocate memory for key_array");
++                goto err;
++            }
++            ka->keys_len= 1;
++            if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
++                  my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
++            {
++                WSREP_ERROR("Can't allocate memory for key_parts");
++                goto err;
++            }
++            ka->keys[0].key_parts_num= 2;
++            if (!wsrep_prepare_key_for_isolation(
++                    db, table,
++                    (wsrep_buf_t*)ka->keys[0].key_parts,
++                    &ka->keys[0].key_parts_num))
++            {
++                WSREP_ERROR("Preparing keys for isolation failed");
++                goto err;
++            }
++        }
++    }
++
++    for (const TABLE_LIST* table= table_list; table; table= table->next_global)
++    {
++        if (!find_temporary_table(thd, table))
++        {
++            wsrep_key_t* tmp;
++            tmp= (wsrep_key_t*)my_realloc(
++                ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(0));
++            if (!tmp)
++            {
++                WSREP_ERROR("Can't allocate memory for key_array");
++                goto err;
++            }
++            ka->keys= tmp;
++            if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
++                  my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
++            {
++                WSREP_ERROR("Can't allocate memory for key_parts");
++                goto err;
++            }
++            ka->keys[ka->keys_len].key_parts_num= 2;
++            ++ka->keys_len;
++            if (!wsrep_prepare_key_for_isolation(
++                    table->db, table->table_name,
++                    (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
++                    &ka->keys[ka->keys_len - 1].key_parts_num))
++            {
++                WSREP_ERROR("Preparing keys for isolation failed");
++                goto err;
++            }
++        }
++    }
++    return true;
++err:
++    wsrep_keys_free(ka);
++    return false;
++}
++
++
++bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
++                                  size_t cache_key_len,
++                                  const uchar* row_id,
++                                  size_t row_id_len,
++                                  wsrep_buf_t* key,
++                                  size_t* key_len)
++{
++    if (*key_len < 3) return false;
++
++    *key_len= 0;
++    switch (wsrep_protocol_version)
++    {
++    case 0:
++    {
++        key[0].ptr = cache_key;
++        key[0].len = cache_key_len;
++
++        *key_len = 1;
++        break;
++    }
++    case 1:
++    case 2:
++    case 3:
++    {
++        key[0].ptr = cache_key;
++        key[0].len = strlen( (char*)cache_key );
++
++        key[1].ptr = cache_key + strlen( (char*)cache_key ) + 1;
++        key[1].len = strlen( (char*)(key[1].ptr) );
++
++        *key_len = 2;
++        break;
++    }
++    default:
++        return false;
++    }
++
++    key[*key_len].ptr = row_id;
++    key[*key_len].len = row_id_len;
++    ++(*key_len);
++
++    return true;
++}
++
++
++/*
++ * Construct Query_log_Event from thd query and serialize it
++ * into buffer.
++ *
++ * Return 0 in case of success, 1 in case of error.
++ */
++int wsrep_to_buf_helper(
++    THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len)
++{
++  IO_CACHE tmp_io_cache;
++  if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
++                       65536, MYF(MY_WME)))
++    return 1;
++  int ret(0);
++
++  if (thd->variables.gtid_next.type == GTID_GROUP)
++  {
++      Gtid_log_event gtid_ev(thd, FALSE, &thd->variables.gtid_next);
++      if (!gtid_ev.is_valid()) ret= 0;
++      if (!ret && gtid_ev.write(&tmp_io_cache)) ret= 1;
++  }
++
++  /* if there is prepare query, add event for it */
++  if (!ret && thd->wsrep_TOI_pre_query)
++  {
++    Query_log_event ev(thd, thd->wsrep_TOI_pre_query,
++                     thd->wsrep_TOI_pre_query_len,
++                     FALSE, FALSE, FALSE, 0);
++    if (ev.write(&tmp_io_cache)) ret= 1;
++  }
++
++  /* continue to append the actual query */
++  Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0);
++  if (!ret && ev.write(&tmp_io_cache)) ret= 1;
++  if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1;
++  close_cached_file(&tmp_io_cache);
++  return ret;
++}
++
++#include "sql_show.h"
++static int
++create_view_query(THD *thd, uchar** buf, size_t* buf_len)
++{
++    LEX *lex= thd->lex;
++    SELECT_LEX *select_lex= &lex->select_lex;
++    TABLE_LIST *first_table= select_lex->table_list.first;
++    TABLE_LIST *views = first_table;
++
++    String buff;
++    const LEX_STRING command[3]=
++      {{ C_STRING_WITH_LEN("CREATE ") },
++       { C_STRING_WITH_LEN("ALTER ") },
++       { C_STRING_WITH_LEN("CREATE OR REPLACE ") }};
++
++    buff.append(command[thd->lex->create_view_mode].str,
++                command[thd->lex->create_view_mode].length);
++
++    if (!lex->definer)
++    {
++      /*
++        DEFINER-clause is missing; we have to create default definer in
++        persistent arena to be PS/SP friendly.
++        If this is an ALTER VIEW then the current user should be set as
++        the definer.
++      */
++
++      if (!(lex->definer= create_default_definer(thd)))
++      {
++        WSREP_WARN("view default definer issue");
++      }
++    }
++
++    views->algorithm    = lex->create_view_algorithm;
++    views->definer.user = lex->definer->user;
++    views->definer.host = lex->definer->host;
++    views->view_suid    = lex->create_view_suid;
++    views->with_check   = lex->create_view_check;
++
++    view_store_options(thd, views, &buff);
++    buff.append(STRING_WITH_LEN("VIEW "));
++    /* Test if user supplied a db (ie: we did not use thd->db) */
++    if (views->db && views->db[0] &&
++        (thd->db == NULL || strcmp(views->db, thd->db)))
++    {
++      append_identifier(thd, &buff, views->db,
++                        views->db_length);
++      buff.append('.');
++    }
++    append_identifier(thd, &buff, views->table_name,
++                      views->table_name_length);
++    if (lex->view_list.elements)
++    {
++      List_iterator_fast<LEX_STRING> names(lex->view_list);
++      LEX_STRING *name;
++      int i;
++
++      for (i= 0; (name= names++); i++)
++      {
++        buff.append(i ? ", " : "(");
++        append_identifier(thd, &buff, name->str, name->length);
++      }
++      buff.append(')');
++    }
++    buff.append(STRING_WITH_LEN(" AS "));
++    //buff.append(views->source.str, views->source.length);
++    buff.append(thd->lex->create_view_select.str,
++                thd->lex->create_view_select.length);
++    //int errcode= query_error_code(thd, TRUE);
++    //if (thd->binlog_query(THD::STMT_QUERY_TYPE,
++    //                      buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcod
++    return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
++}
++
++/*
++  returns: 
++   0: statement was replicated as TOI
++   1: TOI replication was skipped
++  -1: TOI replication failed 
++ */
++static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
++                           const TABLE_LIST* table_list)
++{
++  wsrep_status_t ret(WSREP_WARNING);
++  uchar* buf(0);
++  size_t buf_len(0);
++  int buf_err;
++
++  WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
++              thd->wsrep_exec_mode, thd->query() );
++  switch (thd->lex->sql_command)
++  {
++  case SQLCOM_CREATE_VIEW:
++    buf_err= create_view_query(thd, &buf, &buf_len);
++    break;
++  case SQLCOM_CREATE_PROCEDURE:
++  case SQLCOM_CREATE_SPFUNCTION:
++    buf_err= wsrep_create_sp(thd, &buf, &buf_len);
++    break;
++  case SQLCOM_CREATE_TRIGGER:
++    buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len);
++    break;
++  case SQLCOM_CREATE_EVENT:
++    buf_err= wsrep_create_event_query(thd, &buf, &buf_len);
++    break;
++  case SQLCOM_ALTER_EVENT:
++    buf_err= wsrep_alter_event_query(thd, &buf, &buf_len);
++    break;
++  default:
++    buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), &buf,
++                                 &buf_len);
++    break;
++  }
++
++  wsrep_key_arr_t key_arr= {0, 0};
++  struct wsrep_buf buff = { buf, buf_len };
++  if (!buf_err                                                                &&
++      wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&&
++      key_arr.keys_len > 0                                                    &&
++      WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
++                                               key_arr.keys, key_arr.keys_len,
++                                               &buff, 1,
++                                               &thd->wsrep_trx_meta)))
++  {
++    thd->wsrep_exec_mode= TOTAL_ORDER;
++    wsrep_to_isolation++;
++    if (buf) my_free(buf);
++    wsrep_keys_free(&key_arr);
++    WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
++              thd->wsrep_exec_mode);
++  }
++  else if (key_arr.keys_len > 0) {
++    /* jump to error handler in mysql_execute_command() */
++    WSREP_WARN("TO isolation failed for: %d, sql: %s. Check wsrep "
++               "connection state and retry the query.",
++               ret, (thd->query()) ? thd->query() : "void");
++    my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
++           "your wsrep connection state and retry the query.");
++    if (buf) my_free(buf);
++    wsrep_keys_free(&key_arr);
++    return -1;
++  }
++  else {
++    /* non replicated DDL, affecting temporary tables only */
++    WSREP_DEBUG("TO isolation skipped for: %d, sql: %s."
++              "Only temporary tables affected.",
++              ret, (thd->query()) ? thd->query() : "void");
++    return 1;
++  }
++  return 0;
++}
++
++static void wsrep_TOI_end(THD *thd) {
++  wsrep_status_t ret;
++  wsrep_to_isolation--;
++
++  WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
++              thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void");
++  
++  XID xid;
++  wsrep_xid_init(&xid, &thd->wsrep_trx_meta.gtid.uuid,
++                 thd->wsrep_trx_meta.gtid.seqno);
++  wsrep_set_SE_checkpoint(&xid);
++  WSREP_DEBUG("TO END: %lld, update seqno",
++              (long long)wsrep_thd_trx_seqno(thd));
++  
++  if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) {
++    WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd));
++  }
++  else {
++    WSREP_WARN("TO isolation end failed for: %d, sql: %s",
++               ret, (thd->query()) ? thd->query() : "void");
++  }
++}
++
++static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
++{
++  wsrep_status_t ret(WSREP_WARNING);
++  WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
++               thd->wsrep_exec_mode, thd->query() );
++
++  ret = wsrep->desync(wsrep);
++  if (ret != WSREP_OK)
++  {
++    WSREP_WARN("RSU desync failed %d for %s", ret, thd->query());
++    my_error(ER_LOCK_DEADLOCK, MYF(0));
++    return(ret);
++  }
++  mysql_mutex_lock(&LOCK_wsrep_replaying);
++  wsrep_replaying++;
++  mysql_mutex_unlock(&LOCK_wsrep_replaying);
++
++  if (wsrep_wait_committing_connections_close(5000))
++  {
++    /* no can do, bail out from DDL */
++    WSREP_WARN("RSU failed due to pending transactions, %s", thd->query());
++    mysql_mutex_lock(&LOCK_wsrep_replaying);
++    wsrep_replaying--;
++    mysql_mutex_unlock(&LOCK_wsrep_replaying);
++
++    ret = wsrep->resync(wsrep);
++    if (ret != WSREP_OK)
++    {
++      WSREP_WARN("resync failed %d for %s", ret, thd->query());
++    }
++    my_error(ER_LOCK_DEADLOCK, MYF(0));
++    return(1);
++  }
++
++  wsrep_seqno_t seqno = wsrep->pause(wsrep);
++  if (seqno == WSREP_SEQNO_UNDEFINED)
++  {
++    WSREP_WARN("pause failed %lld for %s", (long long)seqno, thd->query());
++    return(1);
++  }
++  WSREP_DEBUG("paused at %lld", (long long)seqno);
++  thd->variables.wsrep_on = 0;
++  return 0;
++}
++
++static void wsrep_RSU_end(THD *thd)
++{
++  wsrep_status_t ret(WSREP_WARNING);
++  WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
++               thd->wsrep_exec_mode, thd->query() );
++
++
++  mysql_mutex_lock(&LOCK_wsrep_replaying);
++  wsrep_replaying--;
++  mysql_mutex_unlock(&LOCK_wsrep_replaying);
++
++  ret = wsrep->resume(wsrep);
++  if (ret != WSREP_OK)
++  {
++    WSREP_WARN("resume failed %d for %s", ret, thd->query());
++  }
++  ret = wsrep->resync(wsrep);
++  if (ret != WSREP_OK)
++  {
++    WSREP_WARN("resync failed %d for %s", ret, thd->query());
++    return;
++  }
++  thd->variables.wsrep_on = 1;
++}
++
++int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
++                             const TABLE_LIST* table_list)
++{
++
++  /*
++    No isolation for applier or replaying threads.
++   */
++  if (thd->wsrep_exec_mode == REPL_RECV) return 0;
++
++  int ret= 0;
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++
++  if (thd->wsrep_conflict_state == MUST_ABORT)
++  {
++    WSREP_INFO("thread: %lu, %s has been aborted due to multi-master conflict",
++               thd->thread_id, thd->query());
++    mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++    return WSREP_TRX_FAIL;
++  }
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++  DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
++  DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
++
++  if (thd->global_read_lock.can_acquire_protection())
++  {
++    WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu",
++                thd->query(), thd->thread_id);
++    return -1;
++  }
++
++  if (wsrep_debug && thd->mdl_context.has_locks())
++  {
++    WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu",
++                thd->query(), thd->thread_id);
++  }
++
++  /*
++    It makes sense to set auto_increment_* to defaults in TOI operations.
++    Must be done before wsrep_TOI_begin() since Query_log_event encapsulating
++    TOI statement and auto inc variables for wsrep replication is constructed
++    there. Variables are reset back in THD::reset_for_next_command() before
++    processing of next command.
++   */
++  if (wsrep_auto_increment_control)
++  {
++    thd->variables.auto_increment_offset = 1;
++    thd->variables.auto_increment_increment = 1;
++  }
++
++  if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
++  {
++    switch (wsrep_OSU_method_options) {
++    case WSREP_OSU_TOI: ret =  wsrep_TOI_begin(thd, db_, table_,
++                                               table_list); break;
++    case WSREP_OSU_RSU: ret =  wsrep_RSU_begin(thd, db_, table_); break;
++    }
++    switch (ret) {
++    case 0:  thd->wsrep_exec_mode= TOTAL_ORDER; break;
++    case 1: 
++      /* TOI replication skipped, treat as success */ 
++      ret = 0; 
++      break;
++    case -1:
++      /* TOI replication failed, treat as error */ 
++      break;
++    }
++  }
++  return ret;
++}
++
++void wsrep_to_isolation_end(THD *thd)
++{
++  if (thd->wsrep_exec_mode == TOTAL_ORDER)
++  {
++    switch(wsrep_OSU_method_options)
++    {
++    case WSREP_OSU_TOI: wsrep_TOI_end(thd); break;
++    case WSREP_OSU_RSU: wsrep_RSU_end(thd); break;
++    }
++    wsrep_cleanup_transaction(thd);
++  }
++}
++
++#define WSREP_MDL_LOG(severity, msg, req, gra)                                       \
++    WSREP_##severity(                                                          \
++      "%s\n"                                                                   \
++      "request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n"      \
++      "granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)",       \
++      msg,                                                                     \
++      req->thread_id, (long long)wsrep_thd_trx_seqno(req),                     \
++      req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
++      req->get_command(), req->lex->sql_command, req->query(),                       \
++      gra->thread_id, (long long)wsrep_thd_trx_seqno(gra),                     \
++      gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \
++      gra->get_command(), gra->lex->sql_command, gra->query());
++
++bool
++wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
++                          MDL_ticket *ticket
++) {
++  if (!WSREP_ON) return FALSE;
++
++  THD *request_thd  = requestor_ctx->wsrep_get_thd();
++  THD *granted_thd  = ticket->get_ctx()->wsrep_get_thd();
++  bool ret          = FALSE;
++
++  mysql_mutex_lock(&request_thd->LOCK_wsrep_thd);
++  if (request_thd->wsrep_exec_mode == TOTAL_ORDER ||
++      request_thd->wsrep_exec_mode == REPL_RECV)
++  {
++    mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
++    WSREP_MDL_LOG(DEBUG, "MDL conflict ", request_thd, granted_thd);
++    ticket->wsrep_report(wsrep_debug);
++
++    mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd);
++    if (granted_thd->wsrep_exec_mode == TOTAL_ORDER ||
++        granted_thd->wsrep_exec_mode == REPL_RECV)
++    {
++      WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", request_thd, granted_thd);
++      ticket->wsrep_report(true);
++      mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
++      ret = TRUE;
++    }
++    else if (granted_thd->lex->sql_command == SQLCOM_FLUSH)
++    {
++      WSREP_DEBUG("mdl granted over FLUSH BF");
++      ticket->wsrep_report(wsrep_debug);
++      mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
++      ret = TRUE;
++    }
++    else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
++    {
++      WSREP_DEBUG("DROP caused BF abort");
++      ticket->wsrep_report(wsrep_debug);
++      mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
++      wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
++      ret = FALSE;
++    }
++    else if (granted_thd->wsrep_query_state == QUERY_COMMITTING)
++    {
++      WSREP_DEBUG("mdl granted, but commiting thd abort scheduled");
++      ticket->wsrep_report(wsrep_debug);
++      mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
++      wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
++      ret = FALSE;
++    }
++    else
++    {
++      WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", request_thd, granted_thd);
++      ticket->wsrep_report(wsrep_debug);
++      mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
++      wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
++      ret = FALSE;
++    }
++  }
++  else
++  {
++    mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
++  }
++  return ret;
++}
+diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
+new file mode 100644
+index 0000000..3df3911
+--- /dev/null
++++ b/sql/wsrep_mysqld.h
+@@ -0,0 +1,321 @@
++/* Copyright 2008-2013 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#ifndef WSREP_MYSQLD_H
++#define WSREP_MYSQLD_H
++
++#include "mysqld.h"
++typedef struct st_mysql_show_var SHOW_VAR;
++#include <sql_priv.h>
++#include "rpl_gtid.h"
++#include "../wsrep/wsrep_api.h"
++
++#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX
++
++class set_var;
++class THD;
++
++enum wsrep_exec_mode {
++    LOCAL_STATE,
++    REPL_RECV,
++    TOTAL_ORDER,
++    LOCAL_COMMIT
++};
++
++enum wsrep_query_state {
++    QUERY_IDLE,
++    QUERY_EXEC,
++    QUERY_COMMITTING,
++    QUERY_EXITING,
++    QUERY_ROLLINGBACK,
++};
++
++enum wsrep_conflict_state {
++    NO_CONFLICT,
++    MUST_ABORT,
++    ABORTING,
++    ABORTED,
++    MUST_REPLAY,
++    REPLAYING,
++    RETRY_AUTOCOMMIT,
++    CERT_FAILURE,
++};
++
++enum wsrep_consistency_check_mode {
++    NO_CONSISTENCY_CHECK,
++    CONSISTENCY_CHECK_DECLARED,
++    CONSISTENCY_CHECK_RUNNING,
++};
++
++
++// Global wsrep parameters
++extern wsrep_t*    wsrep;
++
++// MySQL wsrep options
++extern const char* wsrep_provider;
++extern const char* wsrep_provider_options;
++extern const char* wsrep_cluster_name;
++extern const char* wsrep_cluster_address;
++extern const char* wsrep_node_name;
++extern const char* wsrep_node_address;
++extern const char* wsrep_node_incoming_address;
++extern const char* wsrep_data_home_dir;
++extern const char* wsrep_dbug_option;
++extern long        wsrep_slave_threads;
++extern int         wsrep_slave_count_change;
++extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug;
++extern my_bool     wsrep_convert_LOCK_to_trx;
++extern ulong       wsrep_retry_autocommit;
++extern my_bool     wsrep_auto_increment_control;
++extern my_bool     wsrep_drupal_282555_workaround;
++extern my_bool     wsrep_incremental_data_collection;
++extern const char* wsrep_start_position;
++extern ulong       wsrep_max_ws_size;
++extern ulong       wsrep_max_ws_rows;
++extern const char* wsrep_notify_cmd;
++extern my_bool     wsrep_certify_nonPK;
++extern long        wsrep_max_protocol_version;
++extern long        wsrep_protocol_version;
++extern ulong       wsrep_forced_binlog_format;
++extern ulong       wsrep_OSU_method_options;
++extern my_bool     wsrep_desync;
++extern my_bool     wsrep_recovery;
++extern my_bool     wsrep_replicate_myisam;
++extern my_bool     wsrep_log_conflicts;
++extern ulong       wsrep_mysql_replication_bundle;
++extern my_bool     wsrep_load_data_splitting;
++extern my_bool     wsrep_restart_slave;
++extern my_bool     wsrep_restart_slave_activated;
++extern my_bool     wsrep_slave_FK_checks;
++extern my_bool     wsrep_slave_UK_checks;
++
++enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU };
++enum enum_wsrep_sync_wait {
++    WSREP_SYNC_WAIT_NONE = 0x0,
++    // show, select, begin
++    WSREP_SYNC_WAIT_BEFORE_READ = 0x1,
++    WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE = 0x2,
++    WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE = 0x4,
++    WSREP_SYNC_WAIT_MAX = 0x7
++};
++
++// MySQL status variables
++extern my_bool     wsrep_connected;
++extern my_bool     wsrep_ready;
++extern const char* wsrep_cluster_state_uuid;
++extern long long   wsrep_cluster_conf_id;
++extern const char* wsrep_cluster_status;
++extern long        wsrep_cluster_size;
++extern long        wsrep_local_index;
++extern long long   wsrep_local_bf_aborts;
++extern const char* wsrep_provider_name;
++extern const char* wsrep_provider_version;
++extern const char* wsrep_provider_vendor;
++
++int  wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
++void wsrep_free_status(THD *thd);
++
++/* Filters out --wsrep-new-cluster oprtion from argv[]
++ * should be called in the very beginning of main() */
++void wsrep_filter_new_cluster (int* argc, char* argv[]);
++
++int  wsrep_init();
++void wsrep_deinit();
++void wsrep_recover();
++bool wsrep_before_SE(); // initialize wsrep before storage
++                        // engines (true) or after (false)
++/* wsrep initialization sequence at startup
++ * @param before wsrep_before_SE() value */
++void wsrep_init_startup(bool before);
++
++
++extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
++extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd);
++extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd);
++extern "C" const char * wsrep_thd_exec_mode_str(THD *thd);
++extern "C" const char * wsrep_thd_conflict_state_str(THD *thd);
++extern "C" const char * wsrep_thd_query_state_str(THD *thd);
++extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
++
++extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
++extern "C" void wsrep_thd_set_query_state(
++        THD *thd, enum wsrep_query_state state);
++extern "C" void wsrep_thd_set_conflict_state(
++        THD *thd, enum wsrep_conflict_state state);
++
++extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id);
++
++extern "C" void wsrep_thd_LOCK(THD *thd);
++extern "C" void wsrep_thd_UNLOCK(THD *thd);
++extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
++extern "C" time_t wsrep_thd_query_start(THD *thd);
++extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
++extern "C" int64_t wsrep_thd_trx_seqno(THD *thd);
++extern "C" query_id_t wsrep_thd_query_id(THD *thd);
++extern "C" char * wsrep_thd_query(THD *thd);
++extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd);
++extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id);
++extern "C" void wsrep_thd_awake(THD *thd, my_bool signal);
++extern "C" int wsrep_thd_retry_counter(THD *thd);
++
++
++extern void wsrep_close_client_connections(my_bool wait_to_end);
++extern int  wsrep_wait_committing_connections_close(int wait_time);
++extern void wsrep_close_applier(THD *thd);
++extern void wsrep_wait_appliers_close(THD *thd);
++extern void wsrep_close_applier_threads(int count);
++extern void wsrep_kill_mysql(THD *thd);
++
++/* new defines */
++extern void wsrep_stop_replication(THD *thd);
++extern bool wsrep_start_replication();
++extern bool wsrep_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
++extern int  wsrep_check_opts (int argc, char* const* argv);
++extern void wsrep_prepend_PATH (const char* path);
++/* some inline functions are defined in wsrep_mysqld_inl.h */
++
++/* Other global variables */
++extern wsrep_seqno_t wsrep_locked_seqno;
++
++#define WSREP_ON \
++  (global_system_variables.wsrep_on)
++
++#define WSREP(thd) \
++  (WSREP_ON && wsrep && (thd && thd->variables.wsrep_on))
++
++#define WSREP_CLIENT(thd) \
++    (WSREP(thd) && thd->wsrep_client_thread)
++
++#define WSREP_EMULATE_BINLOG(thd) \
++  (WSREP(thd) && wsrep_emulate_bin_log)
++
++// MySQL logging functions don't seem to understand long long length modifer.
++// This is a workaround. It also prefixes all messages with "WSREP"
++#define WSREP_LOG(fun, ...)                                       \
++    {                                                             \
++        char msg[1024] = {'\0'};                                  \
++        snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__);           \
++        fun("WSREP: %s", msg);                                    \
++    }
++
++#define WSREP_DEBUG(...)                                                \
++    if (wsrep_debug)     WSREP_LOG(sql_print_information, ##__VA_ARGS__)
++#define WSREP_INFO(...)  WSREP_LOG(sql_print_information, ##__VA_ARGS__)
++#define WSREP_WARN(...)  WSREP_LOG(sql_print_warning,     ##__VA_ARGS__)
++#define WSREP_ERROR(...) WSREP_LOG(sql_print_error,       ##__VA_ARGS__)
++
++#define WSREP_LOG_CONFLICT_THD(thd, role)                                      \
++    WSREP_LOG(sql_print_information,                                         \
++      "%s: \n "                                                                      \
++      "  THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n "          \
++      "  SQL: %s",                                                           \
++      role, wsrep_thd_thread_id(thd), wsrep_thd_exec_mode_str(thd),            \
++      wsrep_thd_query_state_str(thd),                                          \
++      wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd),  \
++      wsrep_thd_query(thd)                                                     \
++    );
++
++#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort)                     \
++  if (wsrep_debug || wsrep_log_conflicts)                                    \
++  {                                                                            \
++    WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\
++      (bf_abort) ? "high priority abort" : "certification failure"             \
++    );                                                                         \
++    if (bf_thd)     WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread");          \
++    if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread");       \
++  }
++
++extern void wsrep_ready_wait();
++
++enum wsrep_trx_status {
++    WSREP_TRX_OK,
++    WSREP_TRX_CERT_FAIL,      /* certification failure, must abort */
++    WSREP_TRX_SIZE_EXCEEDED,  /* trx size exceeded */
++    WSREP_TRX_ERROR,          /* native mysql error */
++};
++
++extern enum wsrep_trx_status
++wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all);
++class Ha_trx_info;
++struct THD_TRANS;
++void wsrep_register_hton(THD* thd, bool all);
++void wsrep_post_commit(THD* thd, bool all);
++void wsrep_brute_force_killer(THD *thd);
++int  wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id);
++
++extern "C" bool wsrep_consistency_check(void *thd_ptr);
++
++/* this is visible for client build so that innodb plugin gets this */
++typedef struct wsrep_aborting_thd {
++  struct wsrep_aborting_thd *next;
++  THD *aborting_thd;
++} *wsrep_aborting_thd_t;
++
++extern mysql_mutex_t LOCK_wsrep_ready;
++extern mysql_cond_t  COND_wsrep_ready;
++extern mysql_mutex_t LOCK_wsrep_sst;
++extern mysql_cond_t  COND_wsrep_sst;
++extern mysql_mutex_t LOCK_wsrep_sst_init;
++extern mysql_cond_t  COND_wsrep_sst_init;
++extern mysql_mutex_t LOCK_wsrep_rollback;
++extern mysql_cond_t  COND_wsrep_rollback;
++extern int wsrep_replaying;
++extern mysql_mutex_t LOCK_wsrep_replaying;
++extern mysql_cond_t  COND_wsrep_replaying;
++extern mysql_mutex_t LOCK_wsrep_slave_threads;
++extern mysql_mutex_t LOCK_wsrep_desync;
++extern wsrep_aborting_thd_t wsrep_aborting_thd;
++extern my_bool       wsrep_emulate_bin_log;
++extern int           wsrep_to_isolation;
++extern rpl_sidno     wsrep_sidno;
++extern my_bool       wsrep_preordered_opt;
++#ifdef HAVE_PSI_INTERFACE
++extern PSI_mutex_key key_LOCK_wsrep_ready;
++extern PSI_mutex_key key_COND_wsrep_ready;
++extern PSI_mutex_key key_LOCK_wsrep_sst;
++extern PSI_cond_key  key_COND_wsrep_sst;
++extern PSI_mutex_key key_LOCK_wsrep_sst_init;
++extern PSI_cond_key  key_COND_wsrep_sst_init;
++extern PSI_mutex_key key_LOCK_wsrep_sst_thread;
++extern PSI_cond_key  key_COND_wsrep_sst_thread;
++extern PSI_mutex_key key_LOCK_wsrep_rollback;
++extern PSI_cond_key  key_COND_wsrep_rollback;
++extern PSI_mutex_key key_LOCK_wsrep_replaying;
++extern PSI_cond_key  key_COND_wsrep_replaying;
++extern PSI_mutex_key key_LOCK_wsrep_slave_threads;
++extern PSI_mutex_key key_LOCK_wsrep_desync;
++#endif /* HAVE_PSI_INTERFACE */
++struct TABLE_LIST;
++int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
++                             const TABLE_LIST* table_list);
++void wsrep_to_isolation_end(THD *thd);
++void wsrep_cleanup_transaction(THD *thd);
++int wsrep_to_buf_helper(
++  THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len);
++int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
++int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
++int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len);
++int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len);
++
++struct xid_t;
++void wsrep_get_SE_checkpoint(xid_t*);
++void wsrep_set_SE_checkpoint(xid_t*);
++void wsrep_init_sidno(const wsrep_uuid_t&);
++void wsrep_xid_init(xid_t*, const wsrep_uuid_t*, wsrep_seqno_t);
++const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*);
++wsrep_seqno_t wsrep_xid_seqno(const xid_t*);
++int wsrep_is_wsrep_xid(const void* xid);
++
++#endif /* WSREP_MYSQLD_H */
+diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc
+new file mode 100644
+index 0000000..0fc76f5
+--- /dev/null
++++ b/sql/wsrep_notify.cc
+@@ -0,0 +1,111 @@
++/* Copyright 2010 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#include <mysqld.h>
++#include "wsrep_priv.h"
++#include "wsrep_utils.h"
++
++const char* wsrep_notify_cmd="";
++
++static const char* _status_str(wsrep_member_status_t status)
++{
++  switch (status)
++  {
++  case WSREP_MEMBER_UNDEFINED: return "Undefined";
++  case WSREP_MEMBER_JOINER:    return "Joiner";
++  case WSREP_MEMBER_DONOR:     return "Donor";
++  case WSREP_MEMBER_JOINED:    return "Joined";
++  case WSREP_MEMBER_SYNCED:    return "Synced";
++  default:                     return "Error(?)";
++  }
++}
++
++void wsrep_notify_status (wsrep_member_status_t    status,
++                          const wsrep_view_info_t* view)
++{
++  if (!wsrep_notify_cmd || 0 == strlen(wsrep_notify_cmd))
++  {
++    WSREP_INFO("wsrep_notify_cmd is not defined, skipping notification.");
++    return;
++  }
++
++  char  cmd_buf[1 << 16]; // this can be long
++  long  cmd_len = sizeof(cmd_buf) - 1;
++  char* cmd_ptr = cmd_buf;
++  long  cmd_off = 0;
++
++  cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, "%s",
++                       wsrep_notify_cmd);
++
++  if (status >= WSREP_MEMBER_UNDEFINED && status < WSREP_MEMBER_ERROR)
++  {
++    cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --status %s",
++                         _status_str(status));
++  }
++  else
++  {
++    /* here we preserve provider error codes */
++    cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
++                         " --status 'Error(%d)'", status);
++  }
++
++  if (0 != view)
++  {
++    char uuid_str[40];
++
++    wsrep_uuid_print (&view->state_id.uuid, uuid_str, sizeof(uuid_str));
++    cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
++                         " --uuid %s", uuid_str);
++
++    cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
++                         " --primary %s", view->view >= 0 ? "yes" : "no");
++
++    cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
++                         " --index %d", view->my_idx);
++
++    if (view->memb_num)
++    {
++        cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --members");
++        
++        for (int i = 0; i < view->memb_num; i++)
++        {
++            wsrep_uuid_print (&view->members[i].id, uuid_str, sizeof(uuid_str));
++            cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
++                                 "%c%s/%s/%s", i > 0 ? ',' : ' ',
++                                 uuid_str, view->members[i].name,
++                                 view->members[i].incoming);
++        }
++    }
++  }
++
++  if (cmd_off == cmd_len)
++  {
++    WSREP_ERROR("Notification buffer too short (%ld). Aborting notification.",
++               cmd_len);
++    return;
++  }
++
++  wsp::process p(cmd_ptr, "r");
++
++  p.wait();
++  int err = p.error();
++
++  if (err)
++  {
++    WSREP_ERROR("Notification command failed: %d (%s): \"%s\"",
++                err, strerror(err), cmd_ptr);
++  }
++}
++
+diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h
+new file mode 100644
+index 0000000..93640fb
+--- /dev/null
++++ b/sql/wsrep_priv.h
+@@ -0,0 +1,51 @@
++/* Copyright 2010 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++//! @file declares symbols private to wsrep integration layer
++
++#ifndef WSREP_PRIV_H
++#define WSREP_PRIV_H
++
++#include "wsrep_mysqld.h"
++#include "../wsrep/wsrep_api.h"
++
++#include <log.h>
++#include <pthread.h>
++#include <cstdio>
++
++void    wsrep_ready_set (my_bool x);
++
++ssize_t wsrep_sst_prepare   (void** msg);
++wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx,
++                                     void* recv_ctx,
++                                     const void* msg, size_t msg_len,
++                                     const wsrep_gtid_t* state_id,
++                                     const char* state, size_t state_len,
++                                     bool bypass);
++
++extern wsrep_uuid_t  local_uuid;
++extern wsrep_seqno_t local_seqno;
++
++// a helper function
++void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t*, wsrep_seqno_t,
++                               const void*, size_t);
++/*! SST thread signals init thread about sst completion */
++void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool);
++
++void wsrep_notify_status (wsrep_member_status_t new_status,
++                          const wsrep_view_info_t* view = 0);
++
++#endif /* WSREP_PRIV_H */
+diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
+new file mode 100644
+index 0000000..ed45674
+--- /dev/null
++++ b/sql/wsrep_sst.cc
+@@ -0,0 +1,1102 @@
++/* Copyright 2008-2012 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#include "wsrep_sst.h"
++
++#include <mysqld.h>
++#include <sql_class.h>
++#include <set_var.h>
++#include <sql_acl.h>
++#include <sql_reload.h>
++#include <sql_parse.h>
++#include "wsrep_priv.h"
++#include "wsrep_utils.h"
++#include <cstdio>
++#include <cstdlib>
++
++extern const char wsrep_defaults_file[];
++extern const char wsrep_defaults_group_suffix[];
++
++#define WSREP_SST_OPT_ROLE     "--role"
++#define WSREP_SST_OPT_ADDR     "--address"
++#define WSREP_SST_OPT_AUTH     "--auth"
++#define WSREP_SST_OPT_DATA     "--datadir"
++#define WSREP_SST_OPT_CONF     "--defaults-file"
++#define WSREP_SST_OPT_CONF_SUFFIX "--defaults-group-suffix"
++#define WSREP_SST_OPT_PARENT   "--parent"
++#define WSREP_SST_OPT_BINLOG   "--binlog"
++
++// mysqldump-specific options
++#define WSREP_SST_OPT_USER     "--user"
++#define WSREP_SST_OPT_PSWD     "--password"
++#define WSREP_SST_OPT_HOST     "--host"
++#define WSREP_SST_OPT_PORT     "--port"
++#define WSREP_SST_OPT_LPORT    "--local-port"
++
++// donor-specific
++#define WSREP_SST_OPT_SOCKET   "--socket"
++#define WSREP_SST_OPT_GTID     "--gtid"
++#define WSREP_SST_OPT_BYPASS   "--bypass"
++
++#define WSREP_SST_MYSQLDUMP       "mysqldump"
++#define WSREP_SST_RSYNC           "rsync"
++#define WSREP_SST_SKIP            "skip"
++#define WSREP_SST_XTRABACKUP      "xtrabackup"
++#define WSREP_SST_XTRABACKUP_V2   "xtrabackup-v2"
++#define WSREP_SST_DEFAULT      WSREP_SST_RSYNC
++#define WSREP_SST_ADDRESS_AUTO "AUTO"
++#define WSREP_SST_AUTH_MASK    "********"
++
++const char* wsrep_sst_method          = WSREP_SST_DEFAULT;
++const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO;
++const char* wsrep_sst_donor           = "";
++      char* wsrep_sst_auth            = NULL;
++
++// container for real auth string
++static const char* sst_auth_real      = NULL;
++my_bool wsrep_sst_donor_rejects_queries = FALSE;
++
++bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var)
++{
++    char   buff[FN_REFLEN];
++    String str(buff, sizeof(buff), system_charset_info), *res;
++    const char* c_str = NULL;
++
++    if ((res   = var->value->val_str(&str)) &&
++        (c_str = res->c_ptr()) &&
++        strlen(c_str) > 0)
++        return 0;
++
++    my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "wsrep_sst_method", c_str ? c_str : "NULL");
++    return 1;
++}
++
++bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type)
++{
++    return 0;
++}
++
++static bool sst_receive_address_check (const char* str)
++{
++    if (!strncasecmp(str, "127.0.0.1", strlen("127.0.0.1")) ||
++        !strncasecmp(str, "localhost", strlen("localhost")))
++    {
++        return 1;
++    }
++
++    return 0;
++}
++
++bool  wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var)
++{
++    const char* c_str = var->value->str_value.c_ptr();
++
++    if (sst_receive_address_check (c_str))
++    {
++        my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "wsrep_sst_receive_address", c_str ? c_str : "NULL");
++        return 1;
++    }
++
++    return 0;
++}
++
++bool wsrep_sst_receive_address_update (sys_var *self, THD* thd,
++                                       enum_var_type type)
++{
++    return 0;
++}
++
++bool wsrep_sst_auth_check (sys_var *self, THD* thd, set_var* var)
++{
++    return 0;
++}
++static bool sst_auth_real_set (const char* value)
++{
++    const char* v = strdup (value);
++
++    if (v)
++    {
++        if (sst_auth_real) free (const_cast<char*>(sst_auth_real));
++        sst_auth_real = v;
++
++        if (strlen(sst_auth_real))
++        {
++          if (wsrep_sst_auth)
++          {
++            my_free ((void*)wsrep_sst_auth);
++            wsrep_sst_auth = my_strdup(WSREP_SST_AUTH_MASK, MYF(0));
++            //strncpy (wsrep_sst_auth, WSREP_SST_AUTH_MASK,
++            //     sizeof(wsrep_sst_auth) - 1);
++          }
++          else
++            wsrep_sst_auth = my_strdup (WSREP_SST_AUTH_MASK, MYF(0));
++        }
++        return 0;
++    }
++
++    return 1;
++}
++
++bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type)
++{
++    return sst_auth_real_set (wsrep_sst_auth);
++}
++
++void wsrep_sst_auth_init (const char* value)
++{
++    if (wsrep_sst_auth == value) wsrep_sst_auth = NULL;
++    if (value) sst_auth_real_set (value);
++}
++
++bool  wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var)
++{
++  return 0;
++}
++
++bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type)
++{
++    return 0;
++}
++
++static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED;
++
++bool wsrep_before_SE()
++{
++  return (wsrep_provider != NULL
++          && strcmp (wsrep_provider,   WSREP_NONE)
++          && strcmp (wsrep_sst_method, WSREP_SST_SKIP)
++          && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP));
++}
++
++static bool            sst_complete = false;
++static bool            sst_needed   = false;
++
++void wsrep_sst_grab ()
++{
++  WSREP_INFO("wsrep_sst_grab()");
++  if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
++  sst_complete = false;
++  mysql_mutex_unlock (&LOCK_wsrep_sst);
++}
++
++// Wait for end of SST
++bool wsrep_sst_wait ()
++{
++  if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
++  while (!sst_complete)
++  {
++    WSREP_INFO("Waiting for SST to complete.");
++    mysql_cond_wait (&COND_wsrep_sst, &LOCK_wsrep_sst);
++  }
++
++  if (local_seqno >= 0)
++  {
++    WSREP_INFO("SST complete, seqno: %lld", (long long) local_seqno);
++  }
++  else
++  {
++    WSREP_ERROR("SST failed: %d (%s)",
++                int(-local_seqno), strerror(-local_seqno));
++  }
++
++  mysql_mutex_unlock (&LOCK_wsrep_sst);
++
++  return (local_seqno >= 0);
++}
++
++// Signal end of SST
++void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid,
++                         wsrep_seqno_t       sst_seqno,
++                         bool                needed)
++{
++  if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
++  if (!sst_complete)
++  {
++    sst_complete = true;
++    sst_needed   = needed;
++    local_uuid   = *sst_uuid;
++    local_seqno  = sst_seqno;
++    mysql_cond_signal (&COND_wsrep_sst);
++  }
++  else
++  {
++    /* This can happen when called from wsrep_synced_cb().
++       At the moment there is no way to check there
++       if main thread is still waiting for signal,
++       so wsrep_sst_complete() is called from there
++       each time wsrep_ready changes from FALSE -> TRUE.
++    */
++    WSREP_DEBUG("Nobody is waiting for SST.");
++  }
++  mysql_mutex_unlock (&LOCK_wsrep_sst);
++}
++
++void wsrep_sst_received (wsrep_t*            const wsrep,
++                         const wsrep_uuid_t* const uuid,
++                         wsrep_seqno_t       const seqno,
++                         const void*         const state,
++                         size_t              const state_len)
++{
++    int const rcode(seqno < 0 ? seqno : 0);
++    wsrep_gtid_t const state_id = {
++        *uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno)
++    };
++    wsrep_init_sidno(state_id.uuid);
++    wsrep->sst_received(wsrep, &state_id, state, state_len, rcode);
++}
++
++// Let applier threads to continue
++void wsrep_sst_continue ()
++{
++  if (sst_needed)
++  {
++    WSREP_INFO("Signalling provider to continue.");
++    wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
++  }
++}
++
++struct sst_thread_arg
++{
++  const char*     cmd;
++  int             err;
++  char*           ret_str;
++  mysql_mutex_t   lock;
++  mysql_cond_t    cond;
++
++  sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0)
++  {
++    mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST);
++    mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL);
++  }
++
++  ~sst_thread_arg()
++  {
++    mysql_cond_destroy  (&cond);
++    mysql_mutex_unlock  (&lock);
++    mysql_mutex_destroy (&lock);
++  }
++};
++
++static int sst_scan_uuid_seqno (const char* str,
++                                wsrep_uuid_t* uuid, wsrep_seqno_t* seqno)
++{
++  int offt = wsrep_uuid_scan (str, strlen(str), uuid);
++  if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt])
++  {
++    *seqno = strtoll (str + offt + 1, NULL, 10);
++    if (*seqno != LLONG_MAX || errno != ERANGE)
++    {
++      return 0;
++    }
++  }
++
++  WSREP_ERROR("Failed to parse uuid:seqno pair: '%s'", str);
++  return EINVAL;
++}
++
++// get rid of trailing \n
++static char* my_fgets (char* buf, size_t buf_len, FILE* stream)
++{
++   char* ret= fgets (buf, buf_len, stream);
++
++   if (ret)
++   {
++       size_t len = strlen(ret);
++       if (len > 0 && ret[len - 1] == '\n') ret[len - 1] = '\0';
++   }
++
++   return ret;
++}
++
++/*
++  Generate opt_binlog_opt_val for sst_donate_other(), sst_prepare_other().
++
++  Returns zero on success, negative error code otherwise.
++
++  String containing binlog name is stored in param ret if binlog is enabled
++  and GTID mode is on, otherwise empty string. Returned string should be
++  freed with my_free().
++ */
++static int generate_binlog_opt_val(char** ret)
++{
++  DBUG_ASSERT(ret);
++  *ret= NULL;
++  if (opt_bin_log && gtid_mode > 0)
++  {
++    assert(opt_bin_logname);
++    *ret= strcmp(opt_bin_logname, "0") ?
++        my_strdup(opt_bin_logname, MYF(0)) : my_strdup("", MYF(0));
++  }
++  else
++  {
++    *ret= my_strdup("", MYF(0));
++  }
++  if (!*ret) return -ENOMEM;
++  return 0;
++}
++
++static void* sst_joiner_thread (void* a)
++{
++  sst_thread_arg* arg= (sst_thread_arg*) a;
++  int err= 1;
++
++  {
++    const char magic[] = "ready";
++    const size_t magic_len = sizeof(magic) - 1;
++    const size_t out_len = 512;
++    char out[out_len];
++
++    WSREP_INFO("Running: '%s'", arg->cmd);
++
++    wsp::process proc (arg->cmd, "r");
++
++    if (proc.pipe() && !proc.error())
++    {
++      const char* tmp= my_fgets (out, out_len, proc.pipe());
++
++      if (!tmp || strlen(tmp) < (magic_len + 2) ||
++          strncasecmp (tmp, magic, magic_len))
++      {
++        WSREP_ERROR("Failed to read '%s <addr>' from: %s\n\tRead: '%s'",
++                    magic, arg->cmd, tmp);
++        proc.wait();
++        if (proc.error()) err = proc.error();
++      }
++      else
++      {
++        err = 0;
++      }
++    }
++    else
++    {
++      err = proc.error();
++      WSREP_ERROR("Failed to execute: %s : %d (%s)",
++                  arg->cmd, err, strerror(err));
++    }
++
++    // signal sst_prepare thread with ret code,
++    // it will go on sending SST request
++    mysql_mutex_lock   (&arg->lock);
++    if (!err)
++    {
++      arg->ret_str = strdup (out + magic_len + 1);
++      if (!arg->ret_str) err = ENOMEM;
++    }
++    arg->err = -err;
++    mysql_cond_signal  (&arg->cond);
++    mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
++
++    if (err) return NULL; /* lp:808417 - return immediately, don't signal
++                           * initializer thread to ensure single thread of
++                           * shutdown. */
++
++    wsrep_uuid_t  ret_uuid  = WSREP_UUID_UNDEFINED;
++    wsrep_seqno_t ret_seqno = WSREP_SEQNO_UNDEFINED;
++
++    // in case of successfull receiver start, wait for SST completion/end
++    char* tmp = my_fgets (out, out_len, proc.pipe());
++
++    proc.wait();
++    err= EINVAL;
++
++    if (!tmp)
++    {
++      WSREP_ERROR("Failed to read uuid:seqno from joiner script.");
++      if (proc.error()) err = proc.error();
++    }
++    else
++    {
++      err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno);
++    }
++
++    if (err)
++    {
++      ret_uuid=  WSREP_UUID_UNDEFINED;
++      ret_seqno= -err;
++    }
++
++    // Tell initializer thread that SST is complete
++    wsrep_sst_complete (&ret_uuid, ret_seqno, true);
++  }
++
++  return NULL;
++}
++
++static ssize_t sst_prepare_other (const char*  method,
++                                  const char*  addr_in,
++                                  const char** addr_out)
++{
++  ssize_t cmd_len= 1024;
++  char    cmd_str[1024];
++  const char* sst_dir= mysql_real_data_home;
++  const char* binlog_opt= "";
++  char* binlog_opt_val= NULL;
++
++  int ret;
++  if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
++  {
++    WSREP_ERROR("sst_prepare_other(): generate_binlog_opt_val() failed: %d",
++                ret);
++    return ret;
++  }
++  if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
++
++
++  ret= snprintf (cmd_str, cmd_len,
++                 "wsrep_sst_%s "
++                 WSREP_SST_OPT_ROLE" 'joiner' "
++                 WSREP_SST_OPT_ADDR" '%s' "
++                 WSREP_SST_OPT_AUTH" '%s' "
++                 WSREP_SST_OPT_DATA" '%s' "
++                 WSREP_SST_OPT_CONF" '%s' "
++                 WSREP_SST_OPT_CONF_SUFFIX" '%s' "
++                 WSREP_SST_OPT_PARENT" '%d'"
++                 " %s '%s' ",
++                 method, addr_in, (sst_auth_real) ? sst_auth_real : "",
++                 sst_dir, wsrep_defaults_file, wsrep_defaults_group_suffix, (int)getpid(),
++                 binlog_opt, binlog_opt_val);
++  my_free(binlog_opt_val);
++
++  if (ret < 0 || ret >= cmd_len)
++  {
++    WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret);
++    return (ret < 0 ? ret : -EMSGSIZE);
++  }
++
++  pthread_t tmp;
++  sst_thread_arg arg(cmd_str);
++  mysql_mutex_lock (&arg.lock);
++  ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
++  if (ret)
++  {
++    WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)",
++                ret, strerror(ret));
++    return ret;
++  }
++  mysql_cond_wait (&arg.cond, &arg.lock);
++
++  *addr_out= arg.ret_str;
++
++  if (!arg.err)
++    ret = strlen(*addr_out);
++  else
++  {
++    assert (arg.err < 0);
++    ret = arg.err;
++  }
++
++  pthread_detach (tmp);
++
++  return ret;
++}
++
++extern uint  mysqld_port;
++
++/*! Just tells donor where to send mysqldump */
++static ssize_t sst_prepare_mysqldump (const char*  addr_in,
++                                      const char** addr_out)
++{
++  ssize_t ret = strlen (addr_in);
++
++  if (!strrchr(addr_in, ':'))
++  {
++    ssize_t s = ret + 7;
++    char* tmp = (char*) malloc (s);
++
++    if (tmp)
++    {
++      ret= snprintf (tmp, s, "%s:%u", addr_in, mysqld_port);
++
++      if (ret > 0 && ret < s)
++      {
++        *addr_out= tmp;
++        return ret;
++      }
++      if (ret > 0) /* buffer too short */ ret = -EMSGSIZE;
++      free (tmp);
++    }
++    else {
++      ret= -ENOMEM;
++    }
++
++    WSREP_ERROR ("Could not prepare state transfer request: "
++                 "adding default port failed: %zd.", ret);
++  }
++  else {
++    *addr_out= addr_in;
++  }
++
++  return ret;
++}
++
++static bool SE_initialized = false;
++
++ssize_t wsrep_sst_prepare (void** msg)
++{
++  const ssize_t ip_max= 256;
++  char ip_buf[ip_max];
++  const char* addr_in=  NULL;
++  const char* addr_out= NULL;
++
++  if (!strcmp(wsrep_sst_method, WSREP_SST_SKIP))
++  {
++    ssize_t ret = strlen(WSREP_STATE_TRANSFER_TRIVIAL) + 1;
++    *msg = strdup(WSREP_STATE_TRANSFER_TRIVIAL);
++    if (!msg)
++    {
++      WSREP_ERROR("Could not allocate %zd bytes for state request", ret);
++      unireg_abort(1);
++    }
++    return ret;
++  }
++
++  // Figure out SST address. Common for all SST methods
++  if (wsrep_sst_receive_address &&
++    strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
++  {
++    addr_in= wsrep_sst_receive_address;
++  }
++  else if (wsrep_node_address && strlen(wsrep_node_address))
++  {
++    const char* const colon= strchr (wsrep_node_address, ':');
++    if (colon)
++    {
++      ptrdiff_t const len= colon - wsrep_node_address;
++      strncpy (ip_buf, wsrep_node_address, len);
++      ip_buf[len]= '\0';
++      addr_in= ip_buf;
++    }
++    else
++    {
++      addr_in= wsrep_node_address;
++    }
++  }
++  else
++  {
++    ssize_t ret= wsrep_guess_ip (ip_buf, ip_max);
++
++    if (ret && ret < ip_max)
++    {
++      addr_in= ip_buf;
++    }
++    else
++    {
++      WSREP_ERROR("Could not prepare state transfer request: "
++                  "failed to guess address to accept state transfer at. "
++                  "wsrep_sst_receive_address must be set manually.");
++      unireg_abort(1);
++    }
++  }
++
++  ssize_t addr_len= -ENOSYS;
++  if (!strcmp(wsrep_sst_method, WSREP_SST_MYSQLDUMP))
++  {
++    addr_len= sst_prepare_mysqldump (addr_in, &addr_out);
++    if (addr_len < 0) unireg_abort(1);
++  }
++  else
++  {
++    /*! A heuristic workaround until we learn how to stop and start engines */
++    if (SE_initialized)
++    {
++      // we already did SST at initializaiton, now engines are running
++      // sql_print_information() is here because the message is too long
++      // for WSREP_INFO.
++      sql_print_information ("WSREP: "
++                 "You have configured '%s' state snapshot transfer method "
++                 "which cannot be performed on a running server. "
++                 "Wsrep provider won't be able to fall back to it "
++                 "if other means of state transfer are unavailable. "
++                 "In that case you will need to restart the server.",
++                 wsrep_sst_method);
++      *msg = 0;
++      return 0;
++    }
++
++    addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out);
++    if (addr_len < 0)
++    {
++      WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
++                   wsrep_sst_method);
++      unireg_abort(1);
++    }
++  }
++
++  size_t const method_len(strlen(wsrep_sst_method));
++  size_t const msg_len   (method_len + addr_len + 2 /* + auth_len + 1*/);
++
++  *msg = malloc (msg_len);
++  if (NULL != *msg) {
++    char* const method_ptr(reinterpret_cast<char*>(*msg));
++    strcpy (method_ptr, wsrep_sst_method);
++    char* const addr_ptr(method_ptr + method_len + 1);
++    strcpy (addr_ptr, addr_out);
++
++    WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr);
++  }
++  else {
++    WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.",
++                msg_len);
++    unireg_abort(1);
++  }
++
++  if (addr_out != addr_in) /* malloc'ed */ free ((char*)addr_out);
++
++  return msg_len;
++}
++
++// helper method for donors
++static int sst_run_shell (const char* cmd_str, int max_tries)
++{
++  int ret = 0;
++
++  for (int tries=1; tries <= max_tries; tries++)
++  {
++    wsp::process proc (cmd_str, "r");
++
++    if (NULL != proc.pipe())
++    {
++      proc.wait();
++    }
++
++    if ((ret = proc.error()))
++    {
++      WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)",
++                  tries, max_tries, proc.cmd(), ret, strerror(ret));
++      sleep (1);
++    }
++    else
++    {
++      WSREP_DEBUG("SST script successfully completed.");
++      break;
++    }
++  }
++
++  return -ret;
++}
++
++static void sst_reject_queries(my_bool close_conn)
++{
++    wsrep_ready_set (FALSE); // this will be resotred when donor becomes synced
++    WSREP_INFO("Rejecting client queries for the duration of SST.");
++    if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
++}
++
++static int sst_mysqldump_check_addr (const char* user, const char* pswd,
++                                     const char* host, const char* port)
++{
++  return 0;
++}
++
++static int sst_donate_mysqldump (const char*         addr,
++                                 const wsrep_uuid_t* uuid,
++                                 const char*         uuid_str,
++                                 wsrep_seqno_t       seqno,
++                                 bool                bypass)
++{
++  size_t host_len;
++  const char* port = strchr (addr, ':');
++
++  if (port)
++  {
++    port += 1;
++    host_len = port - addr;
++  }
++  else
++  {
++    port = "";
++    host_len = strlen (addr) + 1;
++  }
++
++  char *host= (char*) malloc(host_len);
++
++  strncpy (host, addr, host_len - 1);
++  host[host_len - 1] = '\0';
++
++  const char* auth = sst_auth_real;
++  const char* pswd = (auth) ? strchr (auth, ':') : NULL;
++  size_t user_len;
++
++  if (pswd)
++  {
++    pswd += 1;
++    user_len = pswd - auth;
++  }
++  else
++  {
++    pswd = "";
++    user_len = (auth) ? strlen (auth) + 1 : 1;
++  }
++
++  char* user= (char*) malloc(user_len);
++
++  strncpy (user, (auth) ? auth : "", user_len - 1);
++  user[user_len - 1] = '\0';
++
++  int ret = sst_mysqldump_check_addr (user, pswd, host, port);
++  if (!ret)
++  {
++    size_t cmd_len= 1024;
++    char   cmd_str[1024];
++
++    if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
++
++    snprintf (cmd_str, cmd_len,
++              "wsrep_sst_mysqldump "
++              WSREP_SST_OPT_USER" '%s' "
++              WSREP_SST_OPT_PSWD" '%s' "
++              WSREP_SST_OPT_HOST" '%s' "
++              WSREP_SST_OPT_PORT" '%s' "
++              WSREP_SST_OPT_LPORT" '%u' "
++              WSREP_SST_OPT_SOCKET" '%s' "
++              WSREP_SST_OPT_CONF" '%s' "
++              WSREP_SST_OPT_GTID" '%s:%lld'"
++              "%s",
++              user, pswd, host, port, mysqld_port, mysqld_unix_port,
++              wsrep_defaults_file, uuid_str,
++              (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : "");
++
++    WSREP_DEBUG("Running: '%s'", cmd_str);
++
++    ret= sst_run_shell (cmd_str, 3);
++  }
++
++  wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
++
++  wsrep->sst_sent (wsrep, &state_id, ret);
++
++  free(user);
++  free(host);
++
++  return ret;
++}
++
++wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
++
++static int run_sql_command(THD *thd, const char *query)
++{
++  thd->set_query((char *)query, strlen(query));
++
++  Parser_state ps;
++  if (ps.init(thd, thd->query(), thd->query_length()))
++  {
++    WSREP_ERROR("SST query: %s failed", query);
++    return -1;
++  }
++
++  mysql_parse(thd, thd->query(), thd->query_length(), &ps);
++  if (thd->is_error())
++  {
++    int const err= thd->get_stmt_da()->sql_errno();
++    WSREP_WARN ("error executing '%s': %d (%s)%s",
++                query, err, thd->get_stmt_da()->message(),
++                err == ER_UNKNOWN_SYSTEM_VARIABLE ?
++                ". Was mysqld built with --with-innodb-disallow-writes ?" : "");
++    thd->clear_error();
++    return -1;
++  }
++  return 0;
++}
++
++static int sst_flush_tables(THD* thd)
++{
++  WSREP_INFO("Flushing tables for SST...");
++
++  int err;
++  int not_used;
++  if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK"))
++  {
++    WSREP_ERROR("Failed to flush and lock tables");
++    err = -1;
++  }
++  else
++  {
++    /* make sure logs are flushed after global read lock acquired */
++    err= reload_acl_and_cache(thd, REFRESH_ENGINE_LOG | REFRESH_BINARY_LOG,
++                            (TABLE_LIST*) 0, &not_used);
++  }
++
++  if (err)
++  {
++    WSREP_ERROR("Failed to flush tables: %d (%s)", err, strerror(err));
++  }
++  else
++  {
++    WSREP_INFO("Tables flushed.");
++    const char base_name[]= "tables_flushed";
++    ssize_t const full_len= strlen(mysql_real_data_home) + strlen(base_name)+2;
++    char *real_name = (char*) malloc(full_len);
++    sprintf(real_name, "%s/%s", mysql_real_data_home, base_name);
++    char *tmp_name = (char*) malloc(full_len + 4);
++    sprintf(tmp_name, "%s.tmp", real_name);
++
++    FILE* file= fopen(tmp_name, "w+");
++    if (0 == file)
++    {
++      err= errno;
++      WSREP_ERROR("Failed to open '%s': %d (%s)", tmp_name, err,strerror(err));
++    }
++    else
++    {
++      fprintf(file, "%s:%lld\n",
++              wsrep_cluster_state_uuid, (long long)wsrep_locked_seqno);
++      fsync(fileno(file));
++      fclose(file);
++      if (rename(tmp_name, real_name) == -1)
++      {
++        err= errno;
++        WSREP_ERROR("Failed to rename '%s' to '%s': %d (%s)",
++                     tmp_name, real_name, err,strerror(err));
++      }
++    }
++    free(real_name);
++    free(tmp_name);
++  }
++
++  return err;
++}
++
++static void sst_disallow_writes (THD* thd, bool yes)
++{
++  char query_str[64] = { 0, };
++  ssize_t const query_max = sizeof(query_str) - 1;
++  snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d",
++            yes ? 1 : 0);
++
++  if (run_sql_command(thd, query_str))
++  {
++    WSREP_ERROR("Failed to disallow InnoDB writes");
++  }
++}
++
++static void* sst_donor_thread (void* a)
++{
++  sst_thread_arg* arg= (sst_thread_arg*)a;
++
++  WSREP_INFO("Running: '%s'", arg->cmd);
++
++  int  err= 1;
++  bool locked= false;
++
++  const char*  out= NULL;
++  const size_t out_len= 128;
++  char         out_buf[out_len];
++
++  wsrep_uuid_t  ret_uuid= WSREP_UUID_UNDEFINED;
++  wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST
++
++  wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can
++                       // operate with wsrep_ready == OFF
++  wsp::process proc(arg->cmd, "r");
++
++  err= proc.error();
++
++/* Inform server about SST script startup and release TO isolation */
++  mysql_mutex_lock   (&arg->lock);
++  arg->err = -err;
++  mysql_cond_signal  (&arg->cond);
++  mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
++
++  if (proc.pipe() && !err)
++  {
++wait_signal:
++    out= my_fgets (out_buf, out_len, proc.pipe());
++
++    if (out)
++    {
++      const char magic_flush[]= "flush tables";
++      const char magic_cont[]= "continue";
++      const char magic_done[]= "done";
++
++      if (!strcasecmp (out, magic_flush))
++      {
++        err= sst_flush_tables (thd.ptr);
++        if (!err)
++        {
++          sst_disallow_writes (thd.ptr, true);
++          locked= true;
++          goto wait_signal;
++        }
++      }
++      else if (!strcasecmp (out, magic_cont))
++      {
++        if (locked)
++        {
++          sst_disallow_writes (thd.ptr, false);
++          thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
++          locked= false;
++        }
++        err=  0;
++        goto wait_signal;
++      }
++      else if (!strncasecmp (out, magic_done, strlen(magic_done)))
++      {
++        err= sst_scan_uuid_seqno (out + strlen(magic_done) + 1,
++                                  &ret_uuid, &ret_seqno);
++      }
++      else
++      {
++        WSREP_WARN("Received unknown signal: '%s'", out);
++      }
++    }
++    else
++    {
++      WSREP_ERROR("Failed to read from: %s", proc.cmd());
++      proc.wait();
++    }
++    if (!err && proc.error()) err= proc.error();
++  }
++  else
++  {
++    WSREP_ERROR("Failed to execute: %s : %d (%s)",
++                proc.cmd(), err, strerror(err));
++  }
++
++  if (locked) // don't forget to unlock server before return
++  {
++    sst_disallow_writes (thd.ptr, false);
++    thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
++  }
++
++  // signal to donor that SST is over
++  struct wsrep_gtid const state_id = {
++      ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno
++  };
++  wsrep->sst_sent (wsrep, &state_id, -err);
++  proc.wait();
++
++  return NULL;
++}
++
++
++
++static int sst_donate_other (const char*   method,
++                             const char*   addr,
++                             const char*   uuid,
++                             wsrep_seqno_t seqno,
++                             bool          bypass)
++{
++  ssize_t cmd_len = 4096;
++  char    cmd_str[4096];
++  const char* binlog_opt= "";
++  char* binlog_opt_val= NULL;
++
++  int ret;
++  if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
++  {
++    WSREP_ERROR("sst_donate_other(): generate_binlog_opt_val() failed: %d",ret);
++    return ret;
++  }
++  if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
++
++  ret= snprintf (cmd_str, cmd_len,
++                 "wsrep_sst_%s "
++                 WSREP_SST_OPT_ROLE" 'donor' "
++                 WSREP_SST_OPT_ADDR" '%s' "
++                 WSREP_SST_OPT_AUTH" '%s' "
++                 WSREP_SST_OPT_SOCKET" '%s' "
++                 WSREP_SST_OPT_DATA" '%s' "
++                 WSREP_SST_OPT_CONF" '%s' "
++                 WSREP_SST_OPT_CONF_SUFFIX" '%s' "
++                 " %s '%s' "
++                 WSREP_SST_OPT_GTID" '%s:%lld'"
++                 "%s",
++                 method, addr, sst_auth_real, mysqld_unix_port,
++                 mysql_real_data_home, wsrep_defaults_file, wsrep_defaults_group_suffix,
++                 binlog_opt, binlog_opt_val,
++                 uuid, (long long) seqno,
++                 bypass ? " "WSREP_SST_OPT_BYPASS : "");
++  my_free(binlog_opt_val);
++
++  if (ret < 0 || ret >= cmd_len)
++  {
++    WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret);
++    return (ret < 0 ? ret : -EMSGSIZE);
++  }
++
++  if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
++
++  pthread_t tmp;
++  sst_thread_arg arg(cmd_str);
++  mysql_mutex_lock (&arg.lock);
++  ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg);
++  if (ret)
++  {
++    WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)",
++                ret, strerror(ret));
++    return ret;
++  }
++  mysql_cond_wait (&arg.cond, &arg.lock);
++
++  WSREP_INFO("sst_donor_thread signaled with %d", arg.err);
++  return arg.err;
++}
++
++wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
++                                       const void* msg, size_t msg_len,
++                                       const wsrep_gtid_t* current_gtid,
++                                       const char* state, size_t state_len,
++                                       bool bypass)
++{
++  /* This will be reset when sync callback is called.
++   * Should we set wsrep_ready to FALSE here too? */
++//  wsrep_notify_status(WSREP_MEMBER_DONOR);
++  local_status.set(WSREP_MEMBER_DONOR);
++
++  const char* method = (char*)msg;
++  size_t method_len  = strlen (method);
++  const char* data   = method + method_len + 1;
++
++  char uuid_str[37];
++  wsrep_uuid_print (&current_gtid->uuid, uuid_str, sizeof(uuid_str));
++
++  int ret;
++  if (!strcmp (WSREP_SST_MYSQLDUMP, method))
++  {
++    ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
++                               current_gtid->seqno, bypass);
++  }
++  else
++  {
++    ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass);
++  }
++
++  return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
++}
++
++void wsrep_SE_init_grab()
++{
++  if (mysql_mutex_lock (&LOCK_wsrep_sst_init)) abort();
++}
++
++void wsrep_SE_init_wait()
++{
++  while (SE_initialized == false)
++  {
++    mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init);
++  }
++  mysql_mutex_unlock (&LOCK_wsrep_sst_init);
++}
++
++void wsrep_SE_init_done()
++{
++  mysql_cond_signal (&COND_wsrep_sst_init);
++  mysql_mutex_unlock (&LOCK_wsrep_sst_init);
++}
++
++void wsrep_SE_initialized()
++{
++  SE_initialized = true;
++}
+diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h
+new file mode 100644
+index 0000000..b7f0e26
+--- /dev/null
++++ b/sql/wsrep_sst.h
+@@ -0,0 +1,40 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#ifndef WSREP_SST_H
++#define WSREP_SST_H
++
++#include <mysql.h> // my_bool
++
++/* system variables */
++extern const char* wsrep_sst_method;
++extern const char* wsrep_sst_receive_address;
++extern const char* wsrep_sst_donor;
++extern       char* wsrep_sst_auth;
++extern    my_bool  wsrep_sst_donor_rejects_queries;
++
++/*! Synchronizes applier thread start with init thread */
++extern void wsrep_sst_grab();
++/*! Init thread waits for SST completion */
++extern bool wsrep_sst_wait();
++/*! Signals wsrep that initialization is complete, writesets can be applied */
++extern void wsrep_sst_continue();
++
++extern void wsrep_SE_init_grab();   /*! grab init critical section */
++extern void wsrep_SE_init_wait();   /*! wait for SE init to complete */
++extern void wsrep_SE_init_done();   /*! signal that SE init is complte */
++extern void wsrep_SE_initialized(); /*! mark SE initialization complete */
++
++#endif /* WSREP_SST_H */
+diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
+new file mode 100644
+index 0000000..707a8fe
+--- /dev/null
++++ b/sql/wsrep_thd.cc
+@@ -0,0 +1,576 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#include "wsrep_thd.h"
++
++#include "transaction.h"
++#include "rpl_rli.h"
++#include "log_event.h"
++#include "sql_parse.h"
++#include "global_threads.h" // LOCK_thread_count, etc.
++#include "sql_base.h" // close_thread_tables()
++#include "mysqld.h"   // start_wsrep_THD();
++
++static long long wsrep_bf_aborts_counter = 0;
++
++int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff)
++{
++    wsrep_local_bf_aborts = my_atomic_load64(&wsrep_bf_aborts_counter);
++    var->type = SHOW_LONGLONG;
++    var->value = (char*)&wsrep_local_bf_aborts;
++    return 0;
++}
++
++/* must have (&thd->LOCK_wsrep_thd) */
++void wsrep_client_rollback(THD *thd)
++{
++  WSREP_DEBUG("client rollback due to BF abort for (%ld), query: %s",
++              thd->thread_id, thd->query());
++
++  my_atomic_add64(&wsrep_bf_aborts_counter, 1);
++
++  thd->wsrep_conflict_state= ABORTING;
++  mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  trans_rollback(thd);
++
++  if (thd->locked_tables_mode && thd->lock)
++  {
++    WSREP_DEBUG("unlocking tables for BF abort (%ld)", thd->thread_id);
++    thd->locked_tables_list.unlock_locked_tables(thd);
++    thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
++  }
++
++  if (thd->global_read_lock.is_acquired())
++  {
++    WSREP_DEBUG("unlocking GRL for BF abort (%ld)", thd->thread_id);
++    thd->global_read_lock.unlock_global_read_lock(thd);
++  }
++
++  /* Release transactional metadata locks. */
++  thd->mdl_context.release_transactional_locks();
++
++  /* release explicit MDL locks */
++  thd->mdl_context.release_explicit_locks();
++
++  if (thd->get_binlog_table_maps())
++  {
++    WSREP_DEBUG("clearing binlog table map for BF abort (%ld)", thd->thread_id);
++    thd->clear_binlog_table_maps();
++  }
++  mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++  thd->wsrep_conflict_state= ABORTED;
++}
++
++#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1
++#define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2
++#include "rpl_info_factory.h"
++
++static Relay_log_info* wsrep_relay_log_init(const char* log_fname)
++{
++  uint rli_option = INFO_REPOSITORY_DUMMY;
++  Relay_log_info *rli= NULL;
++  rli = Rpl_info_factory::create_rli(rli_option, false);
++  rli->set_rli_description_event(
++      new Format_description_log_event(BINLOG_VERSION));
++
++  return (rli);
++
++#ifdef REMOVED
++  Rpl_info_handler* handler_src= NULL;
++  Rpl_info_handler* handler_dest= NULL;
++  ulong *key_info_idx= NULL;
++  const char *msg= "Failed to allocate memory for the relay log info "
++                   "structure";
++
++  DBUG_ENTER("Rpl_info_factory::create_rli");
++
++  if (!(rli= new Relay_log_info(false
++#ifdef HAVE_PSI_INTERFACE
++                                ,&key_relay_log_info_run_lock,
++                                &key_relay_log_info_data_lock,
++                                &key_relay_log_info_sleep_lock,
++                                &key_relay_log_info_data_cond,
++                                &key_relay_log_info_start_cond,
++                                &key_relay_log_info_stop_cond,
++                                &key_relay_log_info_sleep_cond
++#endif /* HAVE_PSI_INTERFACE */
++                               )))
++    goto err;
++
++  if (!(key_info_idx= new ulong[NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR]))
++     goto err;
++  key_info_idx[0]= server_id;
++  rli->set_idx_info(key_info_idx, NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR);
++
++  if(Rpl_info_factory::init_rli_repositories(rli, rli_option, &handler_src,
++                                             &handler_dest, &msg))
++    goto err;
++
++  if (Rpl_info_factory::decide_repository(rli, rli_option, &handler_src,
++                                          &handler_dest, &msg))
++    goto err;
++
++  DBUG_RETURN(rli);
++err:
++  delete handler_src;
++  delete handler_dest;
++  delete []key_info_idx;
++  if (rli)
++  {
++    /*
++      The handler was previously deleted so we need to remove
++      any reference to it.
++    */
++    rli->set_idx_info(NULL, 0);
++    rli->set_rpl_info_handler(NULL);
++    rli->set_rpl_info_type(INVALID_INFO_REPOSITORY);
++    delete rli;
++  }
++  WSREP_ERROR("Error creating relay log info: %s.", msg);
++  DBUG_RETURN(NULL);
++#endif /* REMOVED */
++}
++
++static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
++{
++  shadow->options       = thd->variables.option_bits;
++  shadow->server_status = thd->server_status;
++  shadow->wsrep_exec_mode = thd->wsrep_exec_mode;
++  shadow->vio           = thd->net.vio;
++
++  if (opt_log_slave_updates)
++    thd->variables.option_bits|= OPTION_BIN_LOG;
++  else
++    thd->variables.option_bits&= ~(OPTION_BIN_LOG);
++
++  if (!thd->wsrep_rli) thd->wsrep_rli= wsrep_relay_log_init("wsrep_relay");
++  thd->wsrep_rli->info_thd = thd;
++
++  thd->wsrep_exec_mode= REPL_RECV;
++  thd->net.vio= 0;
++  thd->clear_error();
++
++  shadow->tx_isolation        = thd->variables.tx_isolation;
++  thd->variables.tx_isolation = ISO_READ_COMMITTED;
++  thd->tx_isolation           = ISO_READ_COMMITTED;
++
++  shadow->db            = thd->db;
++  shadow->db_length     = thd->db_length;
++  thd->reset_db(NULL, 0);
++}
++
++static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
++{
++  thd->variables.option_bits  = shadow->options;
++  thd->server_status          = shadow->server_status;
++  thd->wsrep_exec_mode        = shadow->wsrep_exec_mode;
++  thd->net.vio                = shadow->vio;
++  thd->variables.tx_isolation = shadow->tx_isolation;
++  thd->reset_db(shadow->db, shadow->db_length);
++}
++
++void wsrep_replay_transaction(THD *thd)
++{
++  /* checking if BF trx must be replayed */
++  if (thd->wsrep_conflict_state== MUST_REPLAY) {
++    DBUG_ASSERT(wsrep_thd_trx_seqno(thd));
++    if (thd->wsrep_exec_mode!= REPL_RECV) {
++      if (thd->get_stmt_da()->is_sent())
++      {
++        WSREP_ERROR("replay issue, thd has reported status already");
++      }
++      thd->get_stmt_da()->reset_diagnostics_area();
++
++      thd->wsrep_conflict_state= REPLAYING;
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++
++      mysql_reset_thd_for_next_command(thd);
++      thd->killed= THD::NOT_KILLED;
++      close_thread_tables(thd);
++      if (thd->locked_tables_mode && thd->lock)
++      {
++        WSREP_DEBUG("releasing table lock for replaying (%ld)",
++                    thd->thread_id);
++        thd->locked_tables_list.unlock_locked_tables(thd);
++        thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
++      }
++      thd->mdl_context.release_transactional_locks();
++      /*
++        Replaying will call MYSQL_START_STATEMENT when handling
++        BEGIN Query_log_event so end statement must be called before
++        replaying.
++      */
++      MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
++      thd->m_statement_psi= NULL;
++      thd_proc_info(thd, "wsrep replaying trx");
++      WSREP_DEBUG("replay trx: %s %lld",
++                  thd->query() ? thd->query() : "void",
++                  (long long)wsrep_thd_trx_seqno(thd));
++      struct wsrep_thd_shadow shadow;
++      wsrep_prepare_bf_thd(thd, &shadow);
++
++      /* From trans_begin() */
++      thd->variables.option_bits|= OPTION_BEGIN;
++      thd->server_status|= SERVER_STATUS_IN_TRANS;
++
++      int rcode = wsrep->replay_trx(wsrep,
++                                    &thd->wsrep_ws_handle,
++                                    (void *)thd);
++
++      wsrep_return_from_bf_mode(thd, &shadow);
++      if (thd->wsrep_conflict_state!= REPLAYING)
++        WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state );
++
++      mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++
++      switch (rcode)
++      {
++      case WSREP_OK:
++        thd->wsrep_conflict_state= NO_CONFLICT;
++        wsrep->post_commit(wsrep, &thd->wsrep_ws_handle);
++        WSREP_DEBUG("trx_replay successful for: %ld %llu",
++                    thd->thread_id, (long long)thd->real_id);
++        if (thd->get_stmt_da()->is_sent())
++        {
++          WSREP_WARN("replay ok, thd has reported status");
++        }
++        else if (thd->get_stmt_da()->is_set())
++        {
++          if (thd->get_stmt_da()->status() != Diagnostics_area::DA_OK)
++          {
++            WSREP_WARN("replay ok, thd has error status %d",
++                       thd->get_stmt_da()->status());
++          }
++        }
++        else
++        {
++          my_ok(thd);
++        }
++        break;
++      case WSREP_TRX_FAIL:
++        if (thd->get_stmt_da()->is_sent())
++        {
++          WSREP_ERROR("replay failed, thd has reported status");
++        }
++        else
++        {
++          WSREP_DEBUG("replay failed, rolling back");
++          //my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
++        }
++        thd->wsrep_conflict_state= ABORTED;
++        wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle);
++        break;
++      default:
++        WSREP_ERROR("trx_replay failed for: %d, query: %s",
++                    rcode, thd->query() ? thd->query() : "void");
++        /* we're now in inconsistent state, must abort */
++      mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++        unireg_abort(1);
++        break;
++      }
++
++      wsrep_cleanup_transaction(thd);
++
++      mysql_mutex_lock(&LOCK_wsrep_replaying);
++      wsrep_replaying--;
++      WSREP_DEBUG("replaying decreased: %d, thd: %lu",
++                  wsrep_replaying, thd->thread_id);
++      mysql_cond_broadcast(&COND_wsrep_replaying);
++      mysql_mutex_unlock(&LOCK_wsrep_replaying);
++    }
++  }
++}
++
++static void wsrep_replication_process(THD *thd)
++{
++  int rcode;
++  DBUG_ENTER("wsrep_replication_process");
++
++  struct wsrep_thd_shadow shadow;
++
++  wsrep_prepare_bf_thd(thd, &shadow);
++
++  /* From trans_begin() */
++  thd->variables.option_bits|= OPTION_BEGIN;
++  thd->server_status|= SERVER_STATUS_IN_TRANS;
++
++  rcode = wsrep->recv(wsrep, (void *)thd);
++  DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode));
++
++  WSREP_INFO("applier thread exiting (code:%d)", rcode);
++
++  switch (rcode) {
++  case WSREP_OK:
++  case WSREP_NOT_IMPLEMENTED:
++  case WSREP_CONN_FAIL:
++    /* provider does not support slave operations / disconnected from group,
++     * just close applier thread */
++    break;
++  case WSREP_NODE_FAIL:
++    /* data inconsistency => SST is needed */
++    /* Note: we cannot just blindly restart replication here,
++     * SST might require server restart if storage engines must be
++     * initialized after SST */
++    WSREP_ERROR("node consistency compromised, aborting");
++    wsrep_kill_mysql(thd);
++    break;
++  case WSREP_WARNING:
++  case WSREP_TRX_FAIL:
++  case WSREP_TRX_MISSING:
++    /* these suggests a bug in provider code */
++    WSREP_WARN("bad return from recv() call: %d", rcode);
++    /* fall through to node shutdown */
++  case WSREP_FATAL:
++    /* Cluster connectivity is lost.
++     *
++     * If applier was killed on purpose (KILL_CONNECTION), we
++     * avoid mysql shutdown. This is because the killer will then handle
++     * shutdown processing (or replication restarting)
++     */
++    if (thd->killed != THD::KILL_CONNECTION)
++    {
++      wsrep_kill_mysql(thd);
++    }
++    break;
++  }
++
++  mysql_mutex_lock(&LOCK_thread_count);
++  wsrep_close_applier(thd);
++  mysql_cond_broadcast(&COND_thread_count);
++  mysql_mutex_unlock(&LOCK_thread_count);
++
++  TABLE *tmp;
++  while ((tmp = thd->temporary_tables))
++  {
++    WSREP_WARN("Applier %lu, has temporary tables at exit: %s.%s",
++                  thd->thread_id, 
++                  (tmp->s) ? tmp->s->db.str : "void",
++                  (tmp->s) ? tmp->s->table_name.str : "void");
++  }
++  wsrep_return_from_bf_mode(thd, &shadow);
++  DBUG_VOID_RETURN;
++}
++
++void wsrep_create_appliers(long threads)
++{
++  if (!wsrep_connected)
++  {
++    /* see wsrep_replication_start() for the logic */
++    if (wsrep_cluster_address && strlen(wsrep_cluster_address) &&
++        wsrep_provider && strcasecmp(wsrep_provider, "none"))
++    {
++      WSREP_ERROR("Trying to launch slave threads before creating "
++                  "connection at '%s'", wsrep_cluster_address);
++      assert(0);
++    }
++    return;
++  }
++
++  long wsrep_threads=0;
++  pthread_t hThread;
++  while (wsrep_threads++ < threads) {
++    if (pthread_create(
++      &hThread, &connection_attrib,
++      start_wsrep_THD, (void*)wsrep_replication_process))
++      WSREP_WARN("Can't create thread to manage wsrep replication");
++  }
++}
++
++static void wsrep_rollback_process(THD *thd)
++{
++  DBUG_ENTER("wsrep_rollback_process");
++
++  mysql_mutex_lock(&LOCK_wsrep_rollback);
++  wsrep_aborting_thd= NULL;
++
++  while (thd->killed == THD::NOT_KILLED) {
++    thd_proc_info(thd, "wsrep aborter idle");
++    thd->mysys_var->current_mutex= &LOCK_wsrep_rollback;
++    thd->mysys_var->current_cond=  &COND_wsrep_rollback;
++
++    mysql_cond_wait(&COND_wsrep_rollback,&LOCK_wsrep_rollback);
++
++    WSREP_DEBUG("WSREP rollback thread wakes for signal");
++
++    mysql_mutex_lock(&thd->mysys_var->mutex);
++    thd_proc_info(thd, "wsrep aborter active");
++    thd->mysys_var->current_mutex= 0;
++    thd->mysys_var->current_cond=  0;
++    mysql_mutex_unlock(&thd->mysys_var->mutex);
++
++    /* check for false alarms */
++    if (!wsrep_aborting_thd)
++    {
++      WSREP_DEBUG("WSREP rollback thread has empty abort queue");
++    }
++    /* process all entries in the queue */
++    while (wsrep_aborting_thd) {
++      THD *aborting;
++      wsrep_aborting_thd_t next = wsrep_aborting_thd->next;
++      aborting = wsrep_aborting_thd->aborting_thd;
++      my_free(wsrep_aborting_thd);
++      wsrep_aborting_thd= next;
++      /*
++       * must release mutex, appliers my want to add more
++       * aborting thds in our work queue, while we rollback
++       */
++      mysql_mutex_unlock(&LOCK_wsrep_rollback);
++
++      mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
++      if (aborting->wsrep_conflict_state== ABORTED)
++      {
++        WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d",
++                    (long long)aborting->real_id,
++                    aborting->wsrep_conflict_state);
++
++        mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
++        mysql_mutex_lock(&LOCK_wsrep_rollback);
++        continue;
++      }
++      aborting->wsrep_conflict_state= ABORTING;
++
++      mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
++
++      aborting->store_globals();
++
++      mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
++      wsrep_client_rollback(aborting);
++      WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)",
++                  aborting->thread_id, (long long)aborting->real_id);
++      mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
++
++      mysql_mutex_lock(&LOCK_wsrep_rollback);
++    }
++  }
++
++  mysql_mutex_unlock(&LOCK_wsrep_rollback);
++  sql_print_information("WSREP: rollbacker thread exiting");
++
++  DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting"));
++  DBUG_VOID_RETURN;
++}
++
++void wsrep_create_rollbacker()
++{
++  if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
++  {
++    pthread_t hThread;
++    /* create rollbacker */
++    if (pthread_create( &hThread, &connection_attrib,
++                        start_wsrep_THD, (void*)wsrep_rollback_process))
++      WSREP_WARN("Can't create thread to manage wsrep rollback");
++  }
++}
++
++void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe)
++{ 
++  if (thd_ptr) 
++  {
++    THD* thd = (THD*)thd_ptr;
++    thd->wsrep_PA_safe = safe;
++  }
++}
++
++int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync)
++{ 
++  int state = -1;
++  if (thd_ptr) 
++  {
++    THD* thd = (THD*)thd_ptr;
++    if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    
++    state = thd->wsrep_conflict_state;
++    if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++  return state;
++}
++
++my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync)
++{ 
++  my_bool status = FALSE;
++  if (thd_ptr) 
++  {
++    THD* thd = (THD*)thd_ptr;
++    if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    
++    status = ((thd->wsrep_exec_mode == REPL_RECV)    ||
++            (thd->wsrep_exec_mode == TOTAL_ORDER));
++    if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++  return status;
++}
++
++extern "C"
++my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync)
++{
++  bool status = FALSE;
++  if (thd_ptr) 
++  {
++    THD* thd = (THD*)thd_ptr;
++    if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++    
++    status = ((thd->wsrep_exec_mode == REPL_RECV)    ||
++            (thd->wsrep_exec_mode == TOTAL_ORDER)  ||
++            (thd->wsrep_exec_mode == LOCAL_COMMIT));
++    if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++  return status;
++}
++
++extern "C"
++my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync)
++{
++  bool status = FALSE;
++  if (thd_ptr) 
++  {
++    THD* thd = (THD*)thd_ptr;
++    if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++
++    status = (thd->wsrep_exec_mode == LOCAL_STATE);
++    if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
++  }
++  return status;
++}
++
++int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal)
++{
++  THD *victim_thd = (THD *) victim_thd_ptr;
++  THD *bf_thd     = (THD *) bf_thd_ptr;
++  DBUG_ENTER("wsrep_abort_thd");
++
++  if ( (WSREP(bf_thd) ||
++         ( (WSREP_ON || wsrep_OSU_method_options == WSREP_OSU_RSU) &&
++           bf_thd->wsrep_exec_mode == TOTAL_ORDER) )               &&
++       victim_thd)
++  {
++    WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ?
++                (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id);
++    ha_wsrep_abort_transaction(bf_thd, victim_thd, signal);
++  }
++  else
++  {
++    WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd);
++  }
++
++  DBUG_RETURN(1);
++}
++
++int wsrep_thd_in_locking_session(void *thd_ptr)
++{
++  if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) {
++    return 1;
++  }
++  return 0;
++}
+diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
+new file mode 100644
+index 0000000..cbf03e6
+--- /dev/null
++++ b/sql/wsrep_thd.h
+@@ -0,0 +1,38 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#ifndef WSREP_THD_H
++#define WSREP_THD_H
++
++#include "sql_class.h"
++
++int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff);
++void wsrep_client_rollback(THD *thd);
++void wsrep_replay_transaction(THD *thd);
++void wsrep_create_appliers(long threads);
++void wsrep_create_rollbacker();
++
++int  wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
++                                my_bool signal);
++
++extern void  wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
++extern my_bool  wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
++extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync);
++//extern "C" my_bool  wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
++extern "C" my_bool  wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync);
++extern "C" my_bool  wsrep_thd_is_local(void *thd_ptr, my_bool sync);
++int  wsrep_thd_in_locking_session(void *thd_ptr);
++
++#endif /* WSREP_THD_H */
+diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
+new file mode 100644
+index 0000000..2a073ac
+--- /dev/null
++++ b/sql/wsrep_utils.cc
+@@ -0,0 +1,524 @@
++/* Copyright 2010 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++//! @file some utility functions and classes not directly related to replication
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag
++#endif
++
++#include "wsrep_utils.h"
++#include "wsrep_mysqld.h"
++
++#include <sql_class.h>
++
++#include <spawn.h>    // posix_spawn()
++#include <unistd.h>   // pipe()
++#include <errno.h>    // errno
++#include <string.h>   // strerror()
++#include <sys/wait.h> // waitpid()
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netdb.h>    // getaddrinfo()
++
++#ifdef HAVE_GETIFADDRS
++#include <net/if.h>
++#include <ifaddrs.h>
++#endif // HAVE_GETIFADDRS
++
++extern char** environ; // environment variables
++
++static wsp::string wsrep_PATH;
++
++void
++wsrep_prepend_PATH (const char* path)
++{
++    int count = 0;
++
++    while (environ[count])
++    {
++        if (strncmp (environ[count], "PATH=", 5))
++        {
++            count++;
++            continue;
++        }
++
++        char* const old_path (environ[count]);
++
++        if (strstr (old_path, path)) return; // path already there
++
++        size_t const new_path_len(strlen(old_path) + strlen(":") +
++                                  strlen(path) + 1);
++
++        char* const new_path (reinterpret_cast<char*>(malloc(new_path_len)));
++
++        if (new_path)
++        {
++            snprintf (new_path, new_path_len, "PATH=%s:%s", path,
++                      old_path + strlen("PATH="));
++
++            wsrep_PATH.set (new_path);
++            environ[count] = new_path;
++        }
++        else
++        {
++            WSREP_ERROR ("Failed to allocate 'PATH' environment variable "
++                         "buffer of size %zu.", new_path_len);
++        }
++
++        return;
++    }
++
++    WSREP_ERROR ("Failed to find 'PATH' environment variable. "
++                 "State snapshot transfer may not be working.");
++}
++
++namespace wsp
++{
++
++#define PIPE_READ  0
++#define PIPE_WRITE 1
++#define STDIN_FD   0
++#define STDOUT_FD  1
++
++#ifndef POSIX_SPAWN_USEVFORK
++# define POSIX_SPAWN_USEVFORK 0
++#endif
++
++process::process (const char* cmd, const char* type)
++    : str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0)
++{
++    if (0 == str_)
++    {
++        WSREP_ERROR ("Can't allocate command line of size: %zu", strlen(cmd));
++        err_ = ENOMEM;
++        return;
++    }
++
++    if (0 == strlen(str_))
++    {
++        WSREP_ERROR ("Can't start a process: null or empty command line.");
++        return;
++    }
++
++    if (NULL == type || (strcmp (type, "w") && strcmp(type, "r")))
++    {
++        WSREP_ERROR ("type argument should be either \"r\" or \"w\".");
++        return;
++    }
++
++    int pipe_fds[2] = { -1, };
++    if (::pipe(pipe_fds))
++    {
++        err_ = errno;
++        WSREP_ERROR ("pipe() failed: %d (%s)", err_, strerror(err_));
++        return;
++    }
++
++    // which end of pipe will be returned to parent
++    int const parent_end (strcmp(type,"w") ? PIPE_READ : PIPE_WRITE);
++    int const child_end  (parent_end == PIPE_READ ? PIPE_WRITE : PIPE_READ);
++    int const close_fd   (parent_end == PIPE_READ ? STDOUT_FD : STDIN_FD);
++
++    char* const pargv[4] = { strdup("sh"), strdup("-c"), strdup(str_), NULL };
++    if (!(pargv[0] && pargv[1] && pargv[2]))
++    {
++        err_ = ENOMEM;
++        WSREP_ERROR ("Failed to allocate pargv[] array.");
++        goto cleanup_pipe;
++    }
++
++    posix_spawnattr_t attr;
++    err_ = posix_spawnattr_init (&attr);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawnattr_init() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_pipe;
++    }
++
++    /* make sure that no signlas are masked in child process */
++    sigset_t sigmask_empty; sigemptyset(&sigmask_empty);
++    err_ = posix_spawnattr_setsigmask(&attr, &sigmask_empty);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawnattr_setsigmask() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_attr;
++    }
++
++    /* make sure the following signals are not ignored in child process */
++    sigset_t default_signals; sigemptyset(&default_signals);
++    sigaddset(&default_signals, SIGHUP);
++    sigaddset(&default_signals, SIGINT);
++    sigaddset(&default_signals, SIGQUIT);
++    sigaddset(&default_signals, SIGPIPE);
++    sigaddset(&default_signals, SIGTERM);
++    sigaddset(&default_signals, SIGCHLD);
++    err_ = posix_spawnattr_setsigdefault(&attr, &default_signals);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawnattr_setsigdefault() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_attr;
++    }
++
++    err_ = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF  |
++                                            POSIX_SPAWN_SETSIGMASK |
++            /* start a new process group */ POSIX_SPAWN_SETPGROUP  |
++                                            POSIX_SPAWN_USEVFORK);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawnattr_setflags() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_attr;
++    }
++
++    posix_spawn_file_actions_t fact;
++    err_ = posix_spawn_file_actions_init (&fact);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_attr;
++    }
++
++    // close child's stdout|stdin depending on what we returning
++    err_ = posix_spawn_file_actions_addclose (&fact, close_fd);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_fact;
++    }
++
++    // substitute our pipe descriptor in place of the closed one
++    err_ = posix_spawn_file_actions_adddup2 (&fact,
++                                             pipe_fds[child_end], close_fd);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawn_file_actions_addup2() failed: %d (%s)",
++                     err_, strerror(err_));
++        goto cleanup_fact;
++    }
++
++    err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ);
++    if (err_)
++    {
++        WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)",
++                     pargv[2], err_, strerror(err_));
++        pid_ = 0; // just to make sure it was not messed up in the call
++        goto cleanup_fact;
++    }
++
++    io_ = fdopen (pipe_fds[parent_end], type);
++
++    if (io_)
++    {
++        pipe_fds[parent_end] = -1; // skip close on cleanup
++    }
++    else
++    {
++        err_ = errno;
++        WSREP_ERROR ("fdopen() failed: %d (%s)", err_, strerror(err_));
++    }
++
++cleanup_fact:
++    int err; // to preserve err_ code
++    err = posix_spawn_file_actions_destroy (&fact);
++    if (err)
++    {
++        WSREP_ERROR ("posix_spawn_file_actions_destroy() failed: %d (%s)\n",
++                     err, strerror(err));
++    }
++
++cleanup_attr:
++    err = posix_spawnattr_destroy (&attr);
++    if (err)
++    {
++        WSREP_ERROR ("posix_spawnattr_destroy() failed: %d (%s)",
++                     err, strerror(err));
++    }
++
++cleanup_pipe:
++    if (pipe_fds[0] >= 0) close (pipe_fds[0]);
++    if (pipe_fds[1] >= 0) close (pipe_fds[1]);
++
++    free (pargv[0]);
++    free (pargv[1]);
++    free (pargv[2]);
++}
++
++process::~process ()
++{
++    if (io_)
++    {
++        assert (pid_);
++        assert (str_);
++
++        WSREP_WARN("Closing pipe to child process: %s, PID(%ld) "
++                   "which might still be running.", str_, (long)pid_);
++
++        if (fclose (io_) == -1)
++        {
++            err_ = errno;
++            WSREP_ERROR("fclose() failed: %d (%s)", err_, strerror(err_));
++        }
++    }
++
++    if (str_) free (const_cast<char*>(str_));
++}
++
++int
++process::wait ()
++{
++  if (pid_)
++  {
++      int status;
++      if (-1 == waitpid(pid_, &status, 0))
++      {
++          err_ = errno; assert (err_);
++          WSREP_ERROR("Waiting for process failed: %s, PID(%ld): %d (%s)",
++                      str_, (long)pid_, err_, strerror (err_));
++      }
++      else
++      {                // command completed, check exit status
++          if (WIFEXITED (status)) {
++              err_ = WEXITSTATUS (status);
++          }
++          else {       // command didn't complete with exit()
++              WSREP_ERROR("Process was aborted.");
++              err_ = errno ? errno : ECHILD;
++          }
++
++          if (err_) {
++              switch (err_) /* Translate error codes to more meaningful */
++              {
++              case 126: err_ = EACCES; break; /* Permission denied */
++              case 127: err_ = ENOENT; break; /* No such file or directory */
++              }
++              WSREP_ERROR("Process completed with error: %s: %d (%s)",
++                          str_, err_, strerror(err_));
++          }
++
++          pid_ = 0;
++          if (io_) fclose (io_);
++          io_ = NULL;
++      }
++  }
++  else {
++      assert (NULL == io_);
++      WSREP_ERROR("Command did not run: %s", str_);
++  }
++
++  return err_;
++}
++
++thd::thd (my_bool won) : init(), ptr(new THD)
++{
++  if (ptr)
++  {
++    ptr->thread_stack= (char*) &ptr;
++    ptr->store_globals();
++    ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog
++    ptr->variables.wsrep_on = won;
++    ptr->security_ctx->master_access= ~(ulong)0;
++    lex_start(ptr);
++  }
++}
++
++thd::~thd ()
++{
++  if (ptr)
++  {
++    delete ptr;
++    my_pthread_setspecific_ptr (THR_THD, 0);
++  }
++}
++
++} // namespace wsp
++
++/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */
++unsigned int wsrep_check_ip (const char* const addr)
++{
++  if (addr && 0 == strcasecmp(addr, MY_BIND_ALL_ADDRESSES)) return INADDR_ANY;
++
++  unsigned int ret = INADDR_NONE;
++  struct addrinfo *res, hints;
++
++  memset (&hints, 0, sizeof(hints));
++  hints.ai_flags= AI_PASSIVE/*|AI_ADDRCONFIG*/;
++  hints.ai_socktype= SOCK_STREAM;
++  hints.ai_family= AF_UNSPEC;
++
++  int gai_ret = getaddrinfo(addr, NULL, &hints, &res);
++  if (0 == gai_ret)
++  {
++    if (AF_INET == res->ai_family) /* IPv4 */
++    {
++      struct sockaddr_in* a= (struct sockaddr_in*)res->ai_addr;
++      ret= htonl(a->sin_addr.s_addr);
++    }
++    else /* IPv6 */
++    {
++      struct sockaddr_in6* a= (struct sockaddr_in6*)res->ai_addr;
++      if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
++        ret= INADDR_ANY;
++      else if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr))
++        ret= INADDR_LOOPBACK;
++      else
++        ret= 0xdeadbeef;
++    }
++    freeaddrinfo (res);
++  }
++  else {
++    WSREP_ERROR ("getaddrinfo() failed on '%s': %d (%s)",
++                 addr, gai_ret, gai_strerror(gai_ret));
++  }
++
++  // uint8_t* b= (uint8_t*)&ret;
++  // fprintf (stderr, "########## wsrep_check_ip returning: %hhu.%hhu.%hhu.%hhu\n",
++  //          b[0], b[1], b[2], b[3]);
++
++  return ret;
++}
++
++size_t wsrep_guess_ip (char* buf, size_t buf_len)
++{
++  size_t ip_len = 0;
++
++  if (my_bind_addr_str && my_bind_addr_str[0] != '\0')
++  {
++    unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str);
++
++    if (INADDR_NONE == ip_type) {
++      WSREP_ERROR("Networking not configured, cannot receive state transfer.");
++      return 0;
++    }
++
++    if (INADDR_ANY != ip_type) {
++      strncpy (buf, my_bind_addr_str, buf_len);
++      return strlen(buf);
++    }
++  }
++
++  // mysqld binds to all interfaces - try IP from wsrep_node_address
++  if (wsrep_node_address && wsrep_node_address[0] != '\0') {
++    const char* const colon_ptr = strchr(wsrep_node_address, ':');
++
++    if (colon_ptr)
++      ip_len = colon_ptr - wsrep_node_address;
++    else
++      ip_len = strlen(wsrep_node_address);
++
++    if (ip_len >= buf_len) {
++      WSREP_WARN("default_ip(): buffer too short: %zu <= %zd", buf_len, ip_len);
++      return 0;
++    }
++
++    memcpy (buf, wsrep_node_address, ip_len);
++    buf[ip_len] = '\0';
++    return ip_len;
++  }
++
++
++//
++// getifaddrs() is avaiable at least on Linux since glib 2.3, FreeBSD
++// MAC OS X, opensolaris, Solaris.
++//
++// On platforms which do not support getifaddrs() this function returns
++// a failure and user is prompted to do manual configuration.
++//
++#if HAVE_GETIFADDRS
++  struct ifaddrs *ifaddr, *ifa;
++  if (getifaddrs(&ifaddr) == 0)
++  {
++    for (ifa= ifaddr; ifa != NULL; ifa = ifa->ifa_next)
++    {
++      if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) // TODO AF_INET6
++        continue;
++
++      // Skip loopback interfaces (like lo:127.0.0.1)
++      if (ifa->ifa_flags & IFF_LOOPBACK)
++        continue;
++
++      if (vio_getnameinfo(ifa->ifa_addr, buf, buf_len, NULL, 0, NI_NUMERICHOST))
++        continue;
++
++      freeifaddrs(ifaddr);
++      return strlen(buf);
++    }
++    freeifaddrs(ifaddr);
++  }
++#endif // HAVE_GETIFADDRS
++
++  return 0;
++}
++
++/*
++ * WSREPXid
++ */
++
++#define WSREP_XID_PREFIX "WSREPXid"
++#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN
++#define WSREP_XID_UUID_OFFSET 8
++#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
++#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
++
++void wsrep_xid_init(XID* xid, const wsrep_uuid_t* uuid, wsrep_seqno_t seqno)
++{
++  xid->formatID= 1;
++  xid->gtrid_length= WSREP_XID_GTRID_LEN;
++  xid->bqual_length= 0;
++  memset(xid->data, 0, sizeof(xid->data));
++  memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
++  memcpy(xid->data + WSREP_XID_UUID_OFFSET, uuid, sizeof(wsrep_uuid_t));
++  memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t));
++}
++
++const wsrep_uuid_t* wsrep_xid_uuid(const XID* xid)
++{
++  if (wsrep_is_wsrep_xid(xid))
++    return reinterpret_cast<const wsrep_uuid_t*>(xid->data
++                                                 + WSREP_XID_UUID_OFFSET);
++  else
++    return &WSREP_UUID_UNDEFINED;
++}
++
++wsrep_seqno_t wsrep_xid_seqno(const XID* xid)
++{
++
++  if (wsrep_is_wsrep_xid(xid))
++  {
++    wsrep_seqno_t seqno;
++    memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t));
++    return seqno;
++  }
++  else
++  {
++    return WSREP_SEQNO_UNDEFINED;
++  }
++}
++
++extern
++int wsrep_is_wsrep_xid(const void* xid_ptr)
++{
++  const XID* xid= reinterpret_cast<const XID*>(xid_ptr);
++  return (xid->formatID      == 1                   &&
++          xid->gtrid_length  == WSREP_XID_GTRID_LEN &&
++          xid->bqual_length  == 0                   &&
++          !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN));
++}
+diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
+new file mode 100644
+index 0000000..dfb68bc
+--- /dev/null
++++ b/sql/wsrep_utils.h
+@@ -0,0 +1,207 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#ifndef WSREP_UTILS_H
++#define WSREP_UTILS_H
++
++#include "wsrep_priv.h"
++
++unsigned int wsrep_check_ip (const char* addr);
++size_t wsrep_guess_ip (char* buf, size_t buf_len);
++
++namespace wsp {
++class node_status
++{
++public:
++  node_status() : status(WSREP_MEMBER_UNDEFINED) {}
++  void set(wsrep_member_status_t new_status,
++           const wsrep_view_info_t* view = 0)
++  {
++    if (status != new_status || 0 != view)
++    {
++      wsrep_notify_status(new_status, view);
++      status = new_status;
++    }
++  }
++  wsrep_member_status_t get() const { return status; }
++private:
++  wsrep_member_status_t status;
++};
++} /* namespace wsp */
++
++extern wsp::node_status local_status;
++
++namespace wsp {
++/* A small class to run external programs. */
++class process
++{
++private:
++    const char* const str_;
++    FILE*       io_;
++    int         err_;
++    pid_t       pid_;
++
++public:
++/*! @arg type is a pointer to a null-terminated string which  must  contain
++         either  the  letter  'r'  for  reading  or the letter 'w' for writing.
++ */
++    process  (const char* cmd, const char* type);
++    ~process ();
++
++    FILE* pipe () { return io_;  }
++    int   error() { return err_; }
++    int   wait ();
++    const char* cmd() { return str_; }
++};
++
++class thd
++{
++  class thd_init
++  {
++  public:
++    thd_init()  { my_thread_init(); }
++    ~thd_init() { my_thread_end();  }
++  }
++  init;
++
++  thd (const thd&);
++  thd& operator= (const thd&);
++
++public:
++
++  thd(my_bool wsrep_on);
++  ~thd();
++  THD* const ptr;
++};
++
++class string
++{
++public:
++    string() : string_(0) {}
++    void set(char* str) { if (string_) free (string_); string_ = str; }
++    ~string() { set (0); }
++private:
++    char* string_;
++};
++
++#ifdef REMOVED
++class lock
++{
++  pthread_mutex_t* const mtx_;
++
++public:
++
++  lock (pthread_mutex_t* mtx) : mtx_(mtx)
++  {
++    int err = pthread_mutex_lock (mtx_);
++
++    if (err)
++    {
++      WSREP_ERROR("Mutex lock failed: %s", strerror(err));
++      abort();
++    }
++  }
++
++  virtual ~lock ()
++  {
++    int err = pthread_mutex_unlock (mtx_);
++
++    if (err)
++    {
++      WSREP_ERROR("Mutex unlock failed: %s", strerror(err));
++      abort();
++    }
++  }
++
++  inline void wait (pthread_cond_t* cond)
++  {
++    pthread_cond_wait (cond, mtx_);
++  }
++
++private:
++
++  lock (const lock&);
++  lock& operator=(const lock&);
++
++};
++
++class monitor
++{
++  int             mutable refcnt;
++  pthread_mutex_t mutable mtx;
++  pthread_cond_t  mutable cond;
++
++public:
++
++  monitor() : refcnt(0)
++  {
++    pthread_mutex_init (&mtx, NULL);
++    pthread_cond_init  (&cond, NULL);
++  }
++
++  ~monitor()
++  {
++    pthread_mutex_destroy (&mtx);
++    pthread_cond_destroy  (&cond);
++  }
++
++  void enter() const
++  {
++    lock l(&mtx);
++
++    while (refcnt)
++    {
++      l.wait(&cond);
++    }
++    refcnt++;
++  }
++
++  void leave() const
++  {
++    lock l(&mtx);
++
++    refcnt--;
++    if (refcnt == 0)
++    {
++      pthread_cond_signal (&cond);
++    }
++  }
++
++private:
++
++  monitor (const monitor&);
++  monitor& operator= (const monitor&);
++};
++
++class critical
++{
++  const monitor& mon;
++
++public:
++
++  critical(const monitor& m) : mon(m) { mon.enter(); }
++
++  ~critical() { mon.leave(); }
++
++private:
++
++  critical (const critical&);
++  critical& operator= (const critical&);
++};
++#endif
++
++} // namespace wsrep
++
++#endif /* WSREP_UTILS_H */
+diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
+new file mode 100644
+index 0000000..0eea405
+--- /dev/null
++++ b/sql/wsrep_var.cc
+@@ -0,0 +1,628 @@
++/* Copyright 2008 Codership Oy <http://www.codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
++
++#include "wsrep_var.h"
++
++#include <mysqld.h>
++#include <sql_class.h>
++#include <sql_plugin.h>
++#include <set_var.h>
++#include <sql_acl.h>
++#include "wsrep_priv.h"
++#include "wsrep_thd.h"
++#include <my_dir.h>
++#include <cstdio>
++#include <cstdlib>
++
++#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1"
++#define WSREP_CLUSTER_NAME "my_wsrep_cluster"
++
++const  char* wsrep_provider         = 0;
++const  char* wsrep_provider_options = 0;
++const  char* wsrep_cluster_address  = 0;
++const  char* wsrep_cluster_name     = 0;
++const  char* wsrep_node_name        = 0;
++const  char* wsrep_node_address     = 0;
++const  char* wsrep_node_incoming_address = 0;
++const  char* wsrep_start_position   = 0;
++ulong  wsrep_OSU_method_options;
++
++int wsrep_init_vars()
++{
++  wsrep_provider        = my_strdup(WSREP_NONE, MYF(MY_WME));
++  wsrep_provider_options= my_strdup("", MYF(MY_WME));
++  wsrep_cluster_address = my_strdup("", MYF(MY_WME));
++  wsrep_cluster_name    = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME));
++  wsrep_node_name       = my_strdup("", MYF(MY_WME));
++  wsrep_node_address    = my_strdup("", MYF(MY_WME));
++  wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME));
++  wsrep_start_position  = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME));
++
++  global_system_variables.binlog_format=BINLOG_FORMAT_ROW;
++  return 0;
++}
++
++bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type)
++{
++  if (var_type == OPT_GLOBAL) {
++    // FIXME: this variable probably should be changed only per session
++    thd->variables.wsrep_on = global_system_variables.wsrep_on;
++  }
++  return false;
++}
++
++bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type)
++{
++  // global setting should not affect session setting.
++  // if (var_type == OPT_GLOBAL) {
++  //   thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads;
++  // }
++  if (thd->variables.wsrep_causal_reads) {
++    thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ;
++  } else {
++    thd->variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ;
++  }
++
++  // update global settings too.
++  if (global_system_variables.wsrep_causal_reads) {
++      global_system_variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ;
++  } else {
++      global_system_variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ;
++  }
++  return false;
++}
++
++bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type)
++{
++  // global setting should not affect session setting.
++  // if (var_type == OPT_GLOBAL) {
++  //   thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait;
++  // }
++  thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait &
++          WSREP_SYNC_WAIT_BEFORE_READ;
++
++  // update global settings too
++  global_system_variables.wsrep_causal_reads = global_system_variables.wsrep_sync_wait &
++          WSREP_SYNC_WAIT_BEFORE_READ;
++  return false;
++}
++
++static int wsrep_start_position_verify (const char* start_str)
++{
++  size_t        start_len;
++  wsrep_uuid_t  uuid;
++  ssize_t       uuid_len;
++
++  start_len = strlen (start_str);
++  if (start_len < 34)
++    return 1;
++
++  uuid_len = wsrep_uuid_scan (start_str, start_len, &uuid);
++  if (uuid_len < 0 || (start_len - uuid_len) < 2)
++    return 1;
++
++  if (start_str[uuid_len] != ':') // separator should follow UUID
++    return 1;
++
++  char* endptr;
++  wsrep_seqno_t const seqno __attribute__((unused)) // to avoid GCC warnings
++    (strtoll(&start_str[uuid_len + 1], &endptr, 10));
++
++  if (*endptr == '\0') return 0; // remaining string was seqno
++
++  return 1;
++}
++
++bool wsrep_start_position_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char*   start_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  start_str = res->c_ptr();
++
++  if (!start_str) goto err;
++
++  if (!wsrep_start_position_verify(start_str)) return 0;
++
++err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, 
++           start_str ? start_str : "NULL");
++  return 1;
++}
++
++void wsrep_set_local_position (const char* value)
++{
++  size_t value_len  = strlen (value);
++  size_t uuid_len   = wsrep_uuid_scan (value, value_len, &local_uuid);
++
++  local_seqno = strtoll (value + uuid_len + 1, NULL, 10);
++
++  XID xid;
++  wsrep_xid_init(&xid, &local_uuid, local_seqno);
++  wsrep_set_SE_checkpoint(&xid);
++  WSREP_INFO ("wsrep_start_position var submitted: '%s'", wsrep_start_position);
++}
++
++bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  // since this value passed wsrep_start_position_check, don't check anything
++  // here
++  wsrep_set_local_position (wsrep_start_position);
++
++  if (wsrep) {
++    wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
++  }
++
++  return 0;
++}
++
++void wsrep_start_position_init (const char* val)
++{
++  if (NULL == val || wsrep_start_position_verify (val))
++  {
++    WSREP_ERROR("Bad initial value for wsrep_start_position: %s", 
++                (val ? val : ""));
++    return;
++  }
++
++  wsrep_set_local_position (val);
++}
++
++static bool refresh_provider_options()
++{
++  WSREP_DEBUG("refresh_provider_options: %s", 
++              (wsrep_provider_options) ? wsrep_provider_options : "null");
++  char* opts= wsrep->options_get(wsrep);
++  if (opts)
++  {
++    if (wsrep_provider_options) my_free((void *)wsrep_provider_options);
++    wsrep_provider_options = (char*)my_memdup(opts, strlen(opts) + 1, 
++                                              MYF(MY_WME));
++  }
++  else
++  {
++    WSREP_ERROR("Failed to get provider options");
++    return true;
++  }
++  return false;
++}
++
++static int wsrep_provider_verify (const char* provider_str)
++{
++  MY_STAT   f_stat;
++  char path[FN_REFLEN];
++
++  if (!provider_str || strlen(provider_str)== 0)
++    return 1;
++
++  if (!strcmp(provider_str, WSREP_NONE))
++    return 0;
++
++  if (!unpack_filename(path, provider_str))
++    return 1;
++
++  /* check that provider file exists */
++  memset(&f_stat, 0, sizeof(MY_STAT));
++  if (!my_stat(path, &f_stat, MYF(0)))
++  {
++    return 1;
++  }
++  return 0;
++}
++
++bool wsrep_provider_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char*   provider_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  provider_str = res->c_ptr();
++
++  if (!provider_str) goto err;
++
++  if (!wsrep_provider_verify(provider_str)) return 0;
++
++err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, 
++           provider_str ? provider_str : "NULL");
++  return 1;
++}
++
++bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  bool rcode= false;
++
++  bool wsrep_on_saved= thd->variables.wsrep_on;
++  thd->variables.wsrep_on= false;
++
++  WSREP_DEBUG("wsrep_provider_update: %s", wsrep_provider);
++
++  /* stop replication is heavy operation, and includes closing all client 
++     connections. Closing clients may need to get LOCK_global_system_variables
++     at least in MariaDB.
++
++     Note: releasing LOCK_global_system_variables may cause race condition, if 
++     there can be several concurrent clients changing wsrep_provider
++  */
++  mysql_mutex_unlock(&LOCK_global_system_variables);
++  wsrep_stop_replication(thd);
++  mysql_mutex_lock(&LOCK_global_system_variables);
++
++  wsrep_deinit();
++
++  char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider 
++                                     //when fails
++  if (wsrep_init())
++  {
++    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp);
++    rcode = true;
++  }
++  free(tmp);
++
++  // we sure don't want to use old address with new provider
++  wsrep_cluster_address_init(NULL);
++  wsrep_provider_options_init(NULL);
++
++  thd->variables.wsrep_on= wsrep_on_saved;
++
++  refresh_provider_options();
++
++  return rcode;
++}
++
++void wsrep_provider_init (const char* value)
++{
++  WSREP_DEBUG("wsrep_provider_init: %s -> %s", 
++              (wsrep_provider) ? wsrep_provider : "null", 
++              (value) ? value : "null");
++  if (NULL == value || wsrep_provider_verify (value))
++  {
++    WSREP_ERROR("Bad initial value for wsrep_provider: %s",
++                (value ? value : ""));
++    return;
++  }
++
++  if (wsrep_provider) my_free((void *)wsrep_provider);
++  wsrep_provider = my_strdup(value, MYF(0));
++}
++
++bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var)
++{
++  return 0;
++}
++
++bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type)
++{
++  wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options);
++  if (ret != WSREP_OK)
++  {
++    WSREP_ERROR("Set options returned %d", ret);
++    refresh_provider_options();
++    return true;
++  }
++  return refresh_provider_options();
++}
++
++void wsrep_provider_options_init(const char* value)
++{
++  if (wsrep_provider_options && wsrep_provider_options != value) 
++    my_free((void *)wsrep_provider_options);
++  wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL;
++}
++
++static int wsrep_cluster_address_verify (const char* cluster_address_str)
++{
++  /* There is no predefined address format, it depends on provider. */
++  return 0;
++}
++
++bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char*   cluster_address_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  cluster_address_str = res->c_ptr();
++
++  if (!wsrep_cluster_address_verify(cluster_address_str)) return 0;
++
++ err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, 
++             cluster_address_str ? cluster_address_str : "NULL");
++  return 1    ;
++}
++
++bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  bool wsrep_on_saved= thd->variables.wsrep_on;
++  thd->variables.wsrep_on= false;
++
++  /* stop replication is heavy operation, and includes closing all client 
++     connections. Closing clients may need to get LOCK_global_system_variables
++     at least in MariaDB.
++
++     Note: releasing LOCK_global_system_variables may cause race condition, if 
++     there can be several concurrent clients changing wsrep_provider
++  */
++  mysql_mutex_unlock(&LOCK_global_system_variables);
++  wsrep_stop_replication(thd);
++  mysql_mutex_lock(&LOCK_global_system_variables);
++
++  if (wsrep_start_replication())
++  {
++    wsrep_create_rollbacker();
++    wsrep_create_appliers(wsrep_slave_threads);
++  }
++
++  thd->variables.wsrep_on= wsrep_on_saved;
++
++  return false;
++}
++
++void wsrep_cluster_address_init (const char* value)
++{
++  WSREP_DEBUG("wsrep_cluster_address_init: %s -> %s", 
++              (wsrep_cluster_address) ? wsrep_cluster_address : "null", 
++              (value) ? value : "null");
++
++  if (wsrep_cluster_address) my_free ((void*)wsrep_cluster_address);
++  wsrep_cluster_address = (value) ? my_strdup(value, MYF(0)) : NULL;
++}
++
++bool wsrep_cluster_name_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char* cluster_name_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  cluster_name_str = res->c_ptr();
++
++  if (!cluster_name_str || strlen(cluster_name_str) == 0) goto err;
++
++  return 0;
++
++ err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, 
++             cluster_name_str ? cluster_name_str : "NULL");
++  return 1;
++}
++
++bool wsrep_cluster_name_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  return 0;
++}
++
++bool wsrep_node_name_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char* node_name_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  node_name_str = res->c_ptr();
++
++  if (!node_name_str || strlen(node_name_str) == 0) goto err;
++
++  return 0;
++
++ err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
++           node_name_str ? node_name_str : "NULL");
++  return 1;
++}
++
++bool wsrep_node_name_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  return 0;
++}
++
++// TODO: do something more elaborate, like checking connectivity
++bool wsrep_node_address_check (sys_var *self, THD* thd, set_var* var)
++{
++  char   buff[FN_REFLEN];
++  String str(buff, sizeof(buff), system_charset_info), *res;
++  const char* node_address_str = NULL;
++
++  if (!(res = var->value->val_str(&str))) goto err;
++
++  node_address_str = res->c_ptr();
++
++  if (!node_address_str || strlen(node_address_str) == 0) goto err;
++
++  return 0;
++
++ err:
++
++  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
++           node_address_str ? node_address_str : "NULL");
++  return 1;
++}
++
++bool wsrep_node_address_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  return 0;
++}
++
++void wsrep_node_address_init (const char* value)
++{
++  if (wsrep_node_address && strcmp(wsrep_node_address, value))
++    my_free ((void*)wsrep_node_address);
++
++  wsrep_node_address = (value) ? my_strdup(value, MYF(0)) : NULL;
++}
++
++bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
++{
++  mysql_mutex_lock(&LOCK_wsrep_slave_threads);
++  wsrep_slave_count_change = var->value->val_int() - wsrep_slave_threads;
++  mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
++
++  return 0;
++}
++
++bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  if (wsrep_slave_count_change > 0)
++  {
++    wsrep_create_appliers(wsrep_slave_count_change);
++    wsrep_slave_count_change = 0;
++  }
++  return false;
++}
++
++bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
++{
++  bool new_wsrep_desync = var->value->val_bool();
++  if (wsrep_desync == new_wsrep_desync) {
++    if (new_wsrep_desync) {
++      push_warning (thd, Sql_condition::WARN_LEVEL_WARN,
++                   ER_WRONG_VALUE_FOR_VAR,
++                   "'wsrep_desync' is already ON.");
++    } else {
++      push_warning (thd, Sql_condition::WARN_LEVEL_WARN,
++                   ER_WRONG_VALUE_FOR_VAR,
++                   "'wsrep_desync' is already OFF.");
++    }
++  }
++  return 0;
++}
++
++bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type)
++{
++  wsrep_status_t ret(WSREP_WARNING);
++  if (wsrep_desync) {
++    ret = wsrep->desync (wsrep);
++    if (ret != WSREP_OK) {
++      WSREP_WARN ("SET desync failed %d for %s", ret, thd->query());
++      my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query());
++      return true;
++    }
++  } else {
++    ret = wsrep->resync (wsrep);
++    if (ret != WSREP_OK) {
++      WSREP_WARN ("SET resync failed %d for %s", ret, thd->query());
++      my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query());
++      return true;
++    }
++  }
++  return false;
++}
++
++/*
++ * Status variables stuff below
++ */
++static inline void
++wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep)
++{
++  mysql->name = wsrep->name;
++  switch (wsrep->type) {
++  case WSREP_VAR_INT64:
++    mysql->value = (char*) &wsrep->value._int64;
++    mysql->type  = SHOW_LONGLONG;
++    break;
++  case WSREP_VAR_STRING:
++    mysql->value = (char*) &wsrep->value._string;
++    mysql->type  = SHOW_CHAR_PTR;
++    break;
++  case WSREP_VAR_DOUBLE:
++    mysql->value = (char*) &wsrep->value._double;
++    mysql->type  = SHOW_DOUBLE;
++    break;
++  }
++}
++
++#if DYNAMIC
++// somehow this mysql status thing works only with statically allocated arrays.
++static SHOW_VAR*          mysql_status_vars = NULL;
++static int                mysql_status_len  = -1;
++#else
++static SHOW_VAR           mysql_status_vars[512 + 1];
++static const int          mysql_status_len  = 512;
++#endif
++
++static void export_wsrep_status_to_mysql(THD* thd)
++{
++  int wsrep_status_len, i;
++
++  thd->wsrep_status_vars = wsrep->stats_get(wsrep);
++
++  if (!thd->wsrep_status_vars) {
++    return;
++  }
++
++  for (wsrep_status_len = 0;
++       thd->wsrep_status_vars[wsrep_status_len].name != NULL;
++       wsrep_status_len++) {
++      /* */
++  }
++
++#if DYNAMIC
++  if (wsrep_status_len != mysql_status_len) {
++    void* tmp = realloc (mysql_status_vars,
++                         (wsrep_status_len + 1) * sizeof(SHOW_VAR));
++    if (!tmp) {
++
++      sql_print_error ("Out of memory for wsrep status variables."
++                       "Number of variables: %d", wsrep_status_len);
++      return;
++    }
++
++    mysql_status_len  = wsrep_status_len;
++    mysql_status_vars = (SHOW_VAR*)tmp;
++  }
++  /* @TODO: fix this: */
++#else
++  if (mysql_status_len < wsrep_status_len) wsrep_status_len= mysql_status_len;
++#endif
++
++  for (i = 0; i < wsrep_status_len; i++)
++    wsrep_assign_to_mysql (mysql_status_vars + i, thd->wsrep_status_vars + i);
++
++  mysql_status_vars[wsrep_status_len].name  = NullS;
++  mysql_status_vars[wsrep_status_len].value = NullS;
++  mysql_status_vars[wsrep_status_len].type  = SHOW_LONG;
++}
++
++int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff)
++{
++  export_wsrep_status_to_mysql(thd);
++  var->type= SHOW_ARRAY;
++  var->value= (char *) &mysql_status_vars;
++  return 0;
++}
++
++void wsrep_free_status (THD* thd)
++{
++  if (thd->wsrep_status_vars)
++  {
++    wsrep->stats_free (wsrep, thd->wsrep_status_vars);
++    thd->wsrep_status_vars = 0;
++  }
++}
+diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
+new file mode 100644
+index 0000000..d845987
+--- /dev/null
++++ b/sql/wsrep_var.h
+@@ -0,0 +1,84 @@
++/* Copyright (C) 2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
++
++#ifndef WSREP_VAR_H
++#define WSREP_VAR_H
++
++#define WSREP_NODE_INCOMING_AUTO "AUTO"
++
++// MySQL variables funcs
++
++#include "sql_priv.h"
++class sys_var;
++class set_var;
++class THD;
++
++int wsrep_init_vars();
++
++#define CHECK_ARGS   (sys_var *self, THD* thd, set_var *var)
++#define UPDATE_ARGS  (sys_var *self, THD* thd, enum_var_type type)
++#define DEFAULT_ARGS (THD* thd, enum_var_type var_type)
++#define INIT_ARGS    (const char* opt)
++
++extern bool wsrep_on_update                  UPDATE_ARGS;
++extern bool wsrep_causal_reads_update        UPDATE_ARGS;
++extern bool wsrep_sync_wait_update           UPDATE_ARGS;
++extern bool wsrep_start_position_check       CHECK_ARGS;
++extern bool wsrep_start_position_update      UPDATE_ARGS;
++extern void wsrep_start_position_init        INIT_ARGS;
++
++extern bool wsrep_provider_check             CHECK_ARGS;
++extern bool wsrep_provider_update            UPDATE_ARGS;
++extern void wsrep_provider_init              INIT_ARGS;
++
++extern bool wsrep_provider_options_check     CHECK_ARGS;
++extern bool wsrep_provider_options_update    UPDATE_ARGS;
++extern void wsrep_provider_options_init      INIT_ARGS;
++
++extern bool wsrep_cluster_address_check      CHECK_ARGS;
++extern bool wsrep_cluster_address_update     UPDATE_ARGS;
++extern void wsrep_cluster_address_init       INIT_ARGS;
++
++extern bool wsrep_cluster_name_check         CHECK_ARGS;
++extern bool wsrep_cluster_name_update        UPDATE_ARGS;
++
++extern bool wsrep_node_name_check            CHECK_ARGS;
++extern bool wsrep_node_name_update           UPDATE_ARGS;
++
++extern bool wsrep_node_address_check         CHECK_ARGS;
++extern bool wsrep_node_address_update        UPDATE_ARGS;
++extern void wsrep_node_address_init          INIT_ARGS;
++
++extern bool wsrep_sst_method_check           CHECK_ARGS;
++extern bool wsrep_sst_method_update          UPDATE_ARGS;
++extern void wsrep_sst_method_init            INIT_ARGS;
++
++extern bool wsrep_sst_receive_address_check  CHECK_ARGS;
++extern bool wsrep_sst_receive_address_update UPDATE_ARGS;
++
++extern bool wsrep_sst_auth_check             CHECK_ARGS;
++extern bool wsrep_sst_auth_update            UPDATE_ARGS;
++extern void wsrep_sst_auth_init              INIT_ARGS;
++
++extern bool wsrep_sst_donor_check            CHECK_ARGS;
++extern bool wsrep_sst_donor_update           UPDATE_ARGS;
++
++extern bool wsrep_slave_threads_check        CHECK_ARGS;
++extern bool wsrep_slave_threads_update       UPDATE_ARGS;
++
++extern bool wsrep_desync_check               CHECK_ARGS;
++extern bool wsrep_desync_update              UPDATE_ARGS;
++
++#endif /* WSREP_VAR_H */
+diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
+index 1611fb6..392c9e3 100644
+--- a/storage/innobase/btr/btr0cur.cc
++++ b/storage/innobase/btr/btr0cur.cc
+@@ -2946,7 +2946,9 @@ btr_cur_del_mark_set_clust_rec(
+ #endif /* UNIV_DEBUG */
+       ut_ad(dict_index_is_clust(index));
++#ifndef WITH_WSREP
+       ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
++#endif
+       err = lock_clust_rec_modify_check_and_lock(BTR_NO_LOCKING_FLAG, block,
+                                                  rec, index, offsets, thr);
+diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
+index 8045389..fb5dcae 100644
+--- a/storage/innobase/dict/dict0dict.cc
++++ b/storage/innobase/dict/dict0dict.cc
+@@ -3347,7 +3347,29 @@ dict_foreign_find_index(
+       return(NULL);
+ }
+-
++#ifdef WITH_WSREP
++dict_index_t*
++wsrep_dict_foreign_find_index(
++/*====================*/
++      dict_table_t*   table,  /*!< in: table */
++      const char**    col_names, /*!< in: column names, or NULL
++                                      to use table->col_names */
++      const char**    columns,/*!< in: array of column names */
++      ulint           n_cols, /*!< in: number of columns */
++      dict_index_t*   types_idx, /*!< in: NULL or an index to whose types the
++                                 column types must match */
++      ibool           check_charsets,
++                              /*!< in: whether to check charsets.
++                              only has an effect if types_idx != NULL */
++      ulint           check_null)
++                              /*!< in: nonzero if none of the columns must
++                              be declared NOT NULL */
++{
++      return dict_foreign_find_index(
++              table, col_names, columns, n_cols, types_idx, check_charsets, 
++              check_null);
++}
++#endif /* WITH_WSREP */
+ /**********************************************************************//**
+ Report an error in a foreign key definition. */
+ static
+diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
+index 5891b53..2e2bd06 100644
+--- a/storage/innobase/fts/fts0opt.cc
++++ b/storage/innobase/fts/fts0opt.cc
+@@ -2577,6 +2577,8 @@ fts_optimize_add_table(
+               return;
+       }
++      ut_ad(table->cached && table->fts != NULL);
++
+       /* Make sure table with FTS index cannot be evicted */
+       if (table->can_be_evicted) {
+               dict_table_move_from_lru_to_non_lru(table);
+diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
+index b8f6351..b54ab75 100644
+--- a/storage/innobase/handler/ha_innodb.cc
++++ b/storage/innobase/handler/ha_innodb.cc
+@@ -95,6 +95,9 @@ this program; if not, write to the Free Software Foundation, Inc.,
+ #include "fts0priv.h"
+ #include "page0zip.h"
++#ifdef WITH_WSREP
++#include "dict0priv.h"
++#endif /* WITH_WSREP */
+ enum_tx_isolation thd_get_trx_isolation(const THD* thd);
+ #include "ha_innodb.h"
+@@ -103,6 +106,35 @@ enum_tx_isolation thd_get_trx_isolation(const THD* thd);
+ # ifndef MYSQL_PLUGIN_IMPORT
+ #  define MYSQL_PLUGIN_IMPORT /* nothing */
+ # endif /* MYSQL_PLUGIN_IMPORT */
++#ifdef WITH_WSREP
++#include "../storage/innobase/include/ut0byte.h"
++#include <wsrep_mysqld.h>
++#include <my_md5.h>
++extern my_bool wsrep_certify_nonPK;
++class  binlog_trx_data;
++extern handlerton *binlog_hton;
++
++extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback;
++extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback;
++extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd;
++
++static inline wsrep_ws_handle_t*
++wsrep_ws_handle(THD* thd, const trx_t* trx) {
++      return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd),
++                                     (wsrep_trx_id_t)trx->id);
++}
++
++extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key,
++                                       size_t cache_key_len,
++                                         const uchar* row_id,
++                                         size_t row_id_len,
++                                         wsrep_buf_t* key,
++                                         size_t* key_len);
++
++extern handlerton * wsrep_hton;
++extern TC_LOG* tc_log;
++extern void wsrep_cleanup_transaction(THD *thd);
++#endif /* WITH_WSREP */
+ /** to protect innobase_open_files */
+ static mysql_mutex_t innobase_share_mutex;
+@@ -1152,6 +1184,10 @@ innobase_srv_conc_enter_innodb(
+ /*===========================*/
+       trx_t*  trx)    /*!< in: transaction handle */
+ {
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd) && 
++          wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return;
++#endif /* WITH_WSREP */
+       if (srv_thread_concurrency) {
+               if (trx->n_tickets_to_enter_innodb > 0) {
+@@ -1186,6 +1222,10 @@ innobase_srv_conc_exit_innodb(
+ #ifdef UNIV_SYNC_DEBUG
+       ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+ #endif /* UNIV_SYNC_DEBUG */
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd) && 
++          wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return;
++#endif /* WITH_WSREP */
+       /* This is to avoid making an unnecessary function call. */
+       if (trx->declared_to_be_inside_innodb
+@@ -1306,6 +1346,15 @@ thd_to_trx(
+ {
+       return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr));
+ }
++#ifdef WITH_WSREP
++ulonglong
++thd_to_trx_id(
++/*=======*/
++      THD*    thd)    /*!< in: MySQL thread */
++{
++      return(thd_to_trx(thd)->id);
++}
++#endif
+ /********************************************************************//**
+ Call this function when mysqld passes control to the client. That is to
+@@ -1335,6 +1384,15 @@ innobase_release_temporary_latches(
+       return(0);
+ }
++#ifdef WITH_WSREP
++static int 
++wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, 
++                      my_bool signal);
++static void
++wsrep_fake_trx_id(handlerton* hton, THD *thd);
++static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
++static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
++#endif
+ /********************************************************************//**
+ Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
+ time calls srv_active_wake_master_thread. This function should be used
+@@ -1800,6 +1858,9 @@ int
+ innobase_mysql_tmpfile(void)
+ /*========================*/
+ {
++#ifdef WITH_INNODB_DISALLOW_WRITES
++      os_event_wait(srv_allow_writes_event);
++#endif /* WITH_INNODB_DISALLOW_WRITES */
+       int     fd2 = -1;
+       File    fd;
+@@ -2844,6 +2905,12 @@ innobase_init(
+               innobase_release_temporary_latches;
+       innobase_hton->data = &innodb_api_cb;
++#ifdef WITH_WSREP
++        innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction;
++        innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint;
++        innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint;
++        innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id;
++#endif /* WITH_WSREP */
+       ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
+@@ -3407,10 +3474,30 @@ innobase_commit_low(
+ /*================*/
+       trx_t*  trx)    /*!< in: transaction handle */
+ {
++#ifdef WITH_WSREP
++      THD* thd = (THD*)trx->mysql_thd;
++      const char* tmp = 0;
++      if (wsrep_on((void*)thd)) {
++#ifdef WSREP_PROC_INFO
++              char info[64];
++              info[sizeof(info) - 1] = '\0';
++              snprintf(info, sizeof(info) - 1,
++                       "innobase_commit_low():trx_commit_for_mysql(%lld)",
++                       (long long) wsrep_thd_trx_seqno(thd));
++              tmp = thd_proc_info(thd, info);
++
++#else
++              tmp = thd_proc_info(thd, "innobase_commit_low()");
++#endif /* WSREP_PROC_INFO */
++      }
++#endif /* WITH_WSREP */
+       if (trx_is_started(trx)) {
+               trx_commit_for_mysql(trx);
+       }
++#ifdef WITH_WSREP
++      if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); }
++#endif /* WITH_WSREP */
+ }
+ /*****************************************************************//**
+@@ -4063,7 +4150,11 @@ ha_innobase::max_supported_key_length() const
+       case 8192:
+               return(1536);
+       default:
++#ifdef WITH_WSREP
++              return(3500);
++#else
+               return(3500);
++#endif
+       }
+ }
+@@ -5163,6 +5254,112 @@ get_field_offset(
+ {
+       return((uint) (field->ptr - table->record[0]));
+ }
++#ifdef WITH_WSREP
++UNIV_INTERN
++int
++wsrep_innobase_mysql_sort(
++/*===============*/
++                                      /* out: str contains sort string */
++      int             mysql_type,     /* in: MySQL type */
++      uint            charset_number, /* in: number of the charset */
++      unsigned char*  str,            /* in: data field */
++      unsigned int    str_length,     /* in: data field length,
++                                      not UNIV_SQL_NULL */
++      unsigned int    buf_length)     /* in: total str buffer length */
++
++{
++      CHARSET_INFO*           charset;
++      enum_field_types        mysql_tp;
++      int ret_length =        str_length;
++
++      DBUG_ASSERT(str_length != UNIV_SQL_NULL);
++
++      mysql_tp = (enum_field_types) mysql_type;
++
++      switch (mysql_tp) {
++
++      case MYSQL_TYPE_BIT:
++      case MYSQL_TYPE_STRING:
++      case MYSQL_TYPE_VAR_STRING:
++      case MYSQL_TYPE_TINY_BLOB:
++      case MYSQL_TYPE_MEDIUM_BLOB:
++      case MYSQL_TYPE_BLOB:
++      case MYSQL_TYPE_LONG_BLOB:
++      case MYSQL_TYPE_VARCHAR:
++      {
++              uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'};
++              uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN;
++
++              /* Use the charset number to pick the right charset struct for
++              the comparison. Since the MySQL function get_charset may be
++              slow before Bar removes the mutex operation there, we first
++              look at 2 common charsets directly. */
++
++              if (charset_number == default_charset_info->number) {
++                      charset = default_charset_info;
++              } else if (charset_number == my_charset_latin1.number) {
++                      charset = &my_charset_latin1;
++              } else {
++                      charset = get_charset(charset_number, MYF(MY_WME));
++
++                      if (charset == NULL) {
++                        sql_print_error("InnoDB needs charset %lu for doing "
++                                        "a comparison, but MySQL cannot "
++                                        "find that charset.",
++                                        (ulong) charset_number);
++                              ut_a(0);
++                      }
++              }
++
++              ut_a(str_length <= tmp_length);
++              memcpy(tmp_str, str, str_length);
++
++              if (wsrep_protocol_version < 3) {
++                      tmp_length = charset->coll->strnxfrm(
++                              charset, str, str_length,
++                              str_length, tmp_str, tmp_length, 0);
++                      DBUG_ASSERT(tmp_length <= str_length);
++              } else {
++                      /* strnxfrm will expand the destination string,
++                         protocols < 3 truncated the sorted sring
++                         protocols >= 3 gets full sorted sring
++                      */
++                      tmp_length = charset->coll->strnxfrm(
++                              charset, str, buf_length,
++                              str_length, tmp_str, str_length, 0);
++                      DBUG_ASSERT(tmp_length <= buf_length);
++                      ret_length = tmp_length;
++              }
++ 
++              break;
++      }
++      case MYSQL_TYPE_DECIMAL :
++      case MYSQL_TYPE_TINY :
++      case MYSQL_TYPE_SHORT :
++      case MYSQL_TYPE_LONG :
++      case MYSQL_TYPE_FLOAT :
++      case MYSQL_TYPE_DOUBLE :
++      case MYSQL_TYPE_NULL :
++      case MYSQL_TYPE_TIMESTAMP :
++      case MYSQL_TYPE_LONGLONG :
++      case MYSQL_TYPE_INT24 :
++      case MYSQL_TYPE_DATE :
++      case MYSQL_TYPE_TIME :
++      case MYSQL_TYPE_DATETIME :
++      case MYSQL_TYPE_YEAR :
++      case MYSQL_TYPE_NEWDATE :
++      case MYSQL_TYPE_NEWDECIMAL :
++      case MYSQL_TYPE_ENUM :
++      case MYSQL_TYPE_SET :
++      case MYSQL_TYPE_GEOMETRY :
++              break;
++      default:
++              break;
++      }
++
++      return ret_length;
++}
++#endif // WITH_WSREP
+ /*************************************************************//**
+ InnoDB uses this function to compare two data fields for which the data type
+@@ -5675,6 +5872,307 @@ innobase_read_from_2_little_endian(
+ /*******************************************************************//**
+ Stores a key value for a row to a buffer.
+ @return       key value length as stored in buff */
++#ifdef WITH_WSREP
++UNIV_INTERN
++uint
++wsrep_store_key_val_for_row(
++/*===============================*/
++      THD*            thd,
++      TABLE*          table,
++      uint            keynr,  /*!< in: key number */
++      char*           buff,   /*!< in/out: buffer for the key value (in MySQL
++                              format) */
++      uint            buff_len,/*!< in: buffer length */
++      const uchar*    record,
++      ibool*          key_is_null)/*!< out: full key was null */
++{
++      KEY*            key_info        = table->key_info + keynr;
++      KEY_PART_INFO*  key_part        = key_info->key_part;
++      KEY_PART_INFO*  end             = 
++              key_part + key_info->user_defined_key_parts;
++      char*           buff_start      = buff;
++      enum_field_types mysql_type;
++      Field*          field;
++      uint buff_space = buff_len;
++
++      DBUG_ENTER("wsrep_store_key_val_for_row");
++
++      memset(buff, 0, buff_len);
++      *key_is_null = TRUE;
++
++      for (; key_part != end; key_part++) {
++
++              uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'};
++              ibool part_is_null = FALSE;
++
++              if (key_part->null_bit) {
++                      if (buff_space > 0) {
++                              if (record[key_part->null_offset] 
++                                  & key_part->null_bit) {
++                                      *buff = 1;
++                                      part_is_null = TRUE;
++                              } else {
++                                      *buff = 0;
++                              }
++                              buff++;
++                              buff_space--;
++                      } else {
++                              fprintf (stderr, "WSREP: key truncated: %s\n",
++                                       wsrep_thd_query(thd));
++                      }
++              }
++              if (!part_is_null)  *key_is_null = FALSE;
++              
++              field = key_part->field;
++              mysql_type = field->type();
++
++              if (mysql_type == MYSQL_TYPE_VARCHAR) {
++                                              /* >= 5.0.3 true VARCHAR */
++                      ulint           lenlen;
++                      ulint           len;
++                      const byte*     data;
++                      ulint           key_len;
++                      ulint           true_len;
++                      const CHARSET_INFO* cs;
++                      int             error=0;
++
++                      key_len = key_part->length;
++
++                      if (part_is_null) {
++                              true_len = key_len + 2;
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len = buff_space;
++                              }
++                              buff       += true_len;
++                              buff_space -= true_len;
++                              continue;
++                      }
++                      cs = field->charset();
++
++                      lenlen = (ulint)
++                              (((Field_varstring*)field)->length_bytes);
++
++                      data = row_mysql_read_true_varchar(&len,
++                              (byte*) (record
++                              + (ulint)get_field_offset(table, field)),
++                              lenlen);
++
++                      true_len = len;
++
++                      /* For multi byte character sets we need to calculate
++                      the true length of the key */
++
++                      if (len > 0 && cs->mbmaxlen > 1) {
++                              true_len = (ulint) cs->cset->well_formed_len(cs,
++                                              (const char *) data,
++                                              (const char *) data + len,
++                                                (uint) (key_len / cs->mbmaxlen),
++                                              &error);
++                      }
++
++                      /* In a column prefix index, we may need to truncate
++                      the stored value: */
++
++                      if (true_len > key_len) {
++                              true_len = key_len;
++                      }
++
++                      memcpy(sorted, data, true_len);
++                      true_len = wsrep_innobase_mysql_sort(
++                              mysql_type, cs->number, sorted, true_len, 
++                              REC_VERSION_56_MAX_INDEX_COL_LEN);
++
++                      if (wsrep_protocol_version > 1) {
++                      /* Note that we always reserve the maximum possible
++                         length of the true VARCHAR in the key value, though
++                         only len first bytes after the 2 length bytes contain
++                         actual data. The rest of the space was reset to zero
++                         in the bzero() call above. */
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len = buff_space;
++                              }
++                              memcpy(buff, sorted, true_len);
++                                buff       += true_len;
++                              buff_space -= true_len;
++                        } else {
++                                buff += key_len;
++                        }
++              } else if (mysql_type == MYSQL_TYPE_TINY_BLOB
++                      || mysql_type == MYSQL_TYPE_MEDIUM_BLOB
++                      || mysql_type == MYSQL_TYPE_BLOB
++                      || mysql_type == MYSQL_TYPE_LONG_BLOB
++                      /* MYSQL_TYPE_GEOMETRY data is treated
++                      as BLOB data in innodb. */
++                      || mysql_type == MYSQL_TYPE_GEOMETRY) {
++
++                      const CHARSET_INFO* cs;
++                      ulint           key_len;
++                      ulint           true_len;
++                      int             error=0;
++                      ulint           blob_len;
++                      const byte*     blob_data;
++
++                      ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
++
++                      key_len = key_part->length;
++
++                      if (part_is_null) {
++                              true_len = key_len + 2;
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len = buff_space;
++                              }
++                              buff       += true_len;
++                              buff_space -= true_len;
++
++                              continue;
++                      }
++
++                      cs = field->charset();
++
++                      blob_data = row_mysql_read_blob_ref(&blob_len,
++                              (byte*) (record
++                              + (ulint)get_field_offset(table, field)),
++                                      (ulint) field->pack_length());
++
++                      true_len = blob_len;
++
++                      ut_a(get_field_offset(table, field)
++                              == key_part->offset);
++
++                      /* For multi byte character sets we need to calculate
++                      the true length of the key */
++
++                      if (blob_len > 0 && cs->mbmaxlen > 1) {
++                              true_len = (ulint) cs->cset->well_formed_len(cs,
++                                              (const char *) blob_data,
++                                              (const char *) blob_data
++                                                      + blob_len,
++                                                (uint) (key_len / cs->mbmaxlen),
++                                              &error);
++                      }
++
++                      /* All indexes on BLOB and TEXT are column prefix
++                      indexes, and we may need to truncate the data to be
++                      stored in the key value: */
++
++                      if (true_len > key_len) {
++                              true_len = key_len;
++                      }
++
++                      memcpy(sorted, blob_data, true_len);
++                      true_len = wsrep_innobase_mysql_sort(
++                              mysql_type, cs->number, sorted, true_len,
++                              REC_VERSION_56_MAX_INDEX_COL_LEN);
++
++
++                      /* Note that we always reserve the maximum possible
++                      length of the BLOB prefix in the key value. */
++                        if (wsrep_protocol_version > 1) {
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len = buff_space;
++                              }
++                              buff       += true_len;
++                              buff_space -= true_len;
++                      } else {
++                              buff += key_len;
++                      }
++                      memcpy(buff, sorted, true_len);
++              } else {
++                      /* Here we handle all other data types except the
++                      true VARCHAR, BLOB and TEXT. Note that the column
++                      value we store may be also in a column prefix
++                      index. */
++
++                      const CHARSET_INFO*     cs = NULL;
++                      ulint                   true_len;
++                      ulint                   key_len;
++                      const uchar*            src_start;
++                      int                     error=0;
++                      enum_field_types        real_type;
++
++                      key_len = key_part->length;
++
++                      if (part_is_null) {
++                              true_len = key_len;
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len = buff_space;
++                              }
++                              buff       += true_len;
++                              buff_space -= true_len;
++
++                              continue;
++                      }
++
++                      src_start = record + key_part->offset;
++                      real_type = field->real_type();
++                      true_len = key_len;
++
++                      /* Character set for the field is defined only
++                      to fields whose type is string and real field
++                      type is not enum or set. For these fields check
++                      if character set is multi byte. */
++
++                      if (real_type != MYSQL_TYPE_ENUM
++                              && real_type != MYSQL_TYPE_SET
++                              && ( mysql_type == MYSQL_TYPE_VAR_STRING
++                                      || mysql_type == MYSQL_TYPE_STRING)) {
++
++                              cs = field->charset();
++
++                              /* For multi byte character sets we need to
++                              calculate the true length of the key */
++
++                              if (key_len > 0 && cs->mbmaxlen > 1) {
++
++                                      true_len = (ulint)
++                                              cs->cset->well_formed_len(cs,
++                                                      (const char *)src_start,
++                                                      (const char *)src_start
++                                                              + key_len,
++                                                        (uint) (key_len /
++                                                                cs->mbmaxlen),
++                                                      &error);
++                              }
++                              memcpy(sorted, src_start, true_len);
++                              true_len = wsrep_innobase_mysql_sort(
++                                      mysql_type, cs->number, sorted, true_len,
++                                      REC_VERSION_56_MAX_INDEX_COL_LEN);
++
++                              if (true_len > buff_space) {
++                                      fprintf (stderr,
++                                               "WSREP: key truncated: %s\n",
++                                               wsrep_thd_query(thd));
++                                      true_len   = buff_space;
++                              }
++                              memcpy(buff, sorted, true_len);
++                      } else {
++                              memcpy(buff, src_start, true_len);
++                      }
++                      buff       += true_len;
++                      buff_space -= true_len;
++              }
++      }
++
++      ut_a(buff <= buff_start + buff_len);
++
++      DBUG_RETURN((uint)(buff - buff_start));
++}
++#endif /* WITH_WSREP */
+ UNIV_INTERN
+ uint
+ ha_innobase::store_key_val_for_row(
+@@ -6502,6 +7000,9 @@ ha_innobase::write_row(
+       dberr_t         error;
+       int             error_result= 0;
+       ibool           auto_inc_used= FALSE;
++#ifdef WITH_WSREP
++      ibool           auto_inc_inserted= FALSE; /* if NULL was inserted */
++#endif
+       ulint           sql_command;
+       trx_t*          trx = thd_to_trx(user_thd);
+@@ -6535,8 +7036,20 @@ ha_innobase::write_row(
+       if ((sql_command == SQLCOM_ALTER_TABLE
+            || sql_command == SQLCOM_OPTIMIZE
+            || sql_command == SQLCOM_CREATE_INDEX
++#ifdef WITH_WSREP
++           || (wsrep_on(user_thd) && wsrep_load_data_splitting &&
++               sql_command == SQLCOM_LOAD                      &&
++               !thd_test_options(
++                      user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
++#endif /* WITH_WSREP */
+            || sql_command == SQLCOM_DROP_INDEX)
+           && num_write_row >= 10000) {
++#ifdef WITH_WSREP
++              if (wsrep_on(user_thd) && sql_command == SQLCOM_LOAD) {
++                      WSREP_DEBUG("forced trx split for LOAD: %s", 
++                                  wsrep_thd_query(user_thd));
++              }
++#endif /* WITH_WSREP */
+               /* ALTER TABLE is COMMITted at every 10000 copied rows.
+               The IX table lock for the original table has to be re-issued.
+               As this method will be called on a temporary table where the
+@@ -6570,6 +7083,26 @@ no_commit:
+                       */
+                       ;
+               } else if (src_table == prebuilt->table) {
++#ifdef WITH_WSREP
++                      if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
++                          sql_command == SQLCOM_LOAD                      &&
++                          !thd_test_options(
++                                            user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
++                      {
++                              switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1))
++                              {
++                              case WSREP_TRX_OK:
++                                break;
++                              case WSREP_TRX_SIZE_EXCEEDED:
++                              case WSREP_TRX_CERT_FAIL:
++                              case WSREP_TRX_ERROR:
++                                DBUG_RETURN(1);
++                              }
++
++                              if (tc_log->commit(user_thd, 1)) DBUG_RETURN(1);
++                              wsrep_post_commit(user_thd, TRUE);
++                      }
++#endif /* WITH_WSREP */
+                       /* Source table is not in InnoDB format:
+                       no need to re-acquire locks on it. */
+@@ -6580,6 +7113,25 @@ no_commit:
+                       /* We will need an IX lock on the destination table. */
+                       prebuilt->sql_stat_start = TRUE;
+               } else {
++#ifdef WITH_WSREP
++                      if (wsrep_on(user_thd) && wsrep_load_data_splitting &&
++                          sql_command == SQLCOM_LOAD                      &&
++                          !thd_test_options(
++                                            user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
++                      {
++                              switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1))
++                              {
++                              case WSREP_TRX_OK:
++                                break;
++                              case WSREP_TRX_SIZE_EXCEEDED:
++                              case WSREP_TRX_CERT_FAIL:
++                              case WSREP_TRX_ERROR:
++                                DBUG_RETURN(1);
++                              }
++                              if (tc_log->commit(user_thd, 1))  DBUG_RETURN(1);
++                              wsrep_post_commit(user_thd, TRUE);
++                      }
++#endif /* WITH_WSREP */
+                       /* Ensure that there are no other table locks than
+                       LOCK_IX and LOCK_AUTO_INC on the destination table. */
+@@ -6609,6 +7161,9 @@ no_commit:
+               innobase_get_auto_increment(). */
+               prebuilt->autoinc_error = DB_SUCCESS;
++#ifdef WITH_WSREP
++              auto_inc_inserted= (table->next_number_field->val_int() == 0);
++#endif
+               if ((error_result = update_auto_increment())) {
+                       /* We don't want to mask autoinc overflow errors. */
+@@ -6687,6 +7242,40 @@ no_commit:
+                       case SQLCOM_REPLACE_SELECT:
+                               goto set_max_autoinc;
++#ifdef WITH_WSREP
++                      /* workaround for LP bug #355000, retrying the insert */
++                      case SQLCOM_INSERT:
++
++                              WSREP_DEBUG("DUPKEY error for autoinc\n"
++                                    "THD %ld, value %llu, off %llu inc %llu",
++                                    wsrep_thd_thread_id(current_thd),
++                                    auto_inc,
++                                    prebuilt->autoinc_offset,
++                                    prebuilt->autoinc_increment);
++
++                              if (wsrep_on(current_thd)                     &&
++                                  auto_inc_inserted                         &&
++                                  wsrep_drupal_282555_workaround            &&
++                                  wsrep_thd_retry_counter(current_thd) == 0 &&
++                                  !thd_test_options(current_thd, 
++                                                    OPTION_NOT_AUTOCOMMIT | 
++                                                    OPTION_BEGIN)) {
++                                      WSREP_DEBUG(
++                                          "retrying insert: %s",
++                                          (*wsrep_thd_query(current_thd)) ? 
++                                              wsrep_thd_query(current_thd) : 
++                                              (char *)"void");
++                                      error= DB_SUCCESS;
++                                      wsrep_thd_set_conflict_state(
++                                              current_thd, MUST_ABORT);
++                                        innobase_srv_conc_exit_innodb(
++                                              prebuilt->trx);
++                                        /* jump straight to func exit over
++                                         * later wsrep hooks */
++                                        goto func_exit;
++                              }
++                                break;
++#endif
+                       default:
+                               break;
+                       }
+@@ -6745,6 +7334,20 @@ report_error:
+       error_result = convert_error_code_to_mysql(error,
+                                                  prebuilt->table->flags,
+                                                  user_thd);
++#ifdef WITH_WSREP
++      if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
++          wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) &&
++          (sql_command != SQLCOM_LOAD || 
++           thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) {
++
++              if (wsrep_append_keys(user_thd, false, record, NULL)) {
++                      DBUG_PRINT("wsrep", ("row key failed"));
++                      error_result = HA_ERR_INTERNAL_ERROR;
++                      goto wsrep_error;
++              }
++      }
++wsrep_error:
++#endif
+       if (error_result == HA_FTS_INVALID_DOCID) {
+               my_error(HA_FTS_INVALID_DOCID, MYF(0));
+@@ -6755,7 +7358,88 @@ func_exit:
+       DBUG_RETURN(error_result);
+ }
++#ifdef WITH_WSREP
++#if defined(HAVE_YASSL)
++#include "my_config.h"
++#include "md5.hpp"
++#elif defined(HAVE_OPENSSL)
++#include <openssl/md5.h>
++#endif
++static
++int
++wsrep_calc_row_hash(
++/*================*/
++      byte*           digest,         /*!< in/out: md5 sum */
++      const uchar*    row,            /*!< in: row in MySQL format */
++      TABLE*          table,          /*!< in: table in MySQL data
++                                      dictionary */
++      row_prebuilt_t* prebuilt,       /*!< in: InnoDB prebuilt struct */
++      THD*            thd)            /*!< in: user thread */
++{
++      Field*          field;
++      enum_field_types field_mysql_type;
++      uint            n_fields;
++      ulint           len;
++      const byte*     ptr;
++      ulint           col_type;
++      uint            i;
++
++      void *ctx = wsrep_md5_init();
++
++      n_fields = table->s->fields;
++
++      for (i = 0; i < n_fields; i++) {
++              byte null_byte=0;
++              byte true_byte=1;
++
++              field = table->field[i];
++
++              ptr = (const byte*) row + get_field_offset(table, field);
++              len = field->pack_length();
++
++              field_mysql_type = field->type();
++
++              col_type = prebuilt->table->cols[i].mtype;
++
++              switch (col_type) {
++
++              case DATA_BLOB:
++                      ptr = row_mysql_read_blob_ref(&len, ptr, len);
++
++                      break;
++
++              case DATA_VARCHAR:
++              case DATA_BINARY:
++              case DATA_VARMYSQL:
++                      if (field_mysql_type == MYSQL_TYPE_VARCHAR) {
++                              /* This is a >= 5.0.3 type true VARCHAR where
++                              the real payload data length is stored in
++                              1 or 2 bytes */
++
++                              ptr = row_mysql_read_true_varchar(
++                                      &len, ptr,
++                                      (ulint)
++                                      (((Field_varstring*)field)->length_bytes));
++
++                      }
++
++                      break;
++              default:
++                      ;
++              }
++
++              if (field->is_null_in_record(row)) {
++                      wsrep_md5_update(ctx, (char*)&null_byte, 1);
++              } else {
++                      wsrep_md5_update(ctx, (char*)&true_byte, 1);
++                      wsrep_md5_update(ctx, (char*)ptr, len);
++              }
++      }
++      wsrep_compute_md5_hash((char*)digest, ctx);
++      return(0);
++}
++#endif /* WITH_WSREP */
+ /**********************************************************************//**
+ Checks which fields have changed in a row and stores information
+ of them to an update vector.
+@@ -7164,6 +7848,20 @@ func_exit:
+       innobase_active_small();
++#ifdef WITH_WSREP
++      if (!err && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
++            wsrep_on(user_thd)) {
++
++              DBUG_PRINT("wsrep", ("update row key"));
++
++              if (wsrep_append_keys(user_thd, false, old_row, new_row)) {
++                      DBUG_PRINT("wsrep", ("row key failed"));
++                      err = HA_ERR_INTERNAL_ERROR;
++                      goto wsrep_error;
++              }
++      }
++wsrep_error:
++#endif
+       DBUG_RETURN(err);
+ }
+@@ -7211,6 +7909,18 @@ ha_innobase::delete_row(
+       innobase_active_small();
++#ifdef WITH_WSREP
++      if (error == DB_SUCCESS && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
++            wsrep_on(user_thd)) {
++
++              if (wsrep_append_keys(user_thd, false, record, NULL)) {
++                      DBUG_PRINT("wsrep", ("delete fail"));
++                      error = DB_ERROR;
++                      goto wsrep_error;
++              }
++      }
++wsrep_error:
++#endif
+       DBUG_RETURN(convert_error_code_to_mysql(
+                           error, prebuilt->table->flags, user_thd));
+ }
+@@ -8198,7 +8908,6 @@ innobase_fts_create_doc_id_key(
+       dfield_t*       dfield = dtuple_get_nth_field(tuple, 0);
+       ut_a(dict_index_get_n_unique(index) == 1);
+-
+       dtuple_set_n_fields(tuple, index->n_fields);
+       dict_index_copy_types(tuple, index, index->n_fields);
+@@ -8371,7 +9080,395 @@ ha_innobase::ft_end()
+       rnd_end();
+ }
++#ifdef WITH_WSREP
++dict_index_t*
++wsrep_dict_foreign_find_index(
++      dict_table_t*   table,
++      const char**    col_names,
++      const char**    columns,
++      ulint           n_cols,
++      dict_index_t*   types_idx,
++      ibool           check_charsets,
++      ulint           check_null);
++
++extern
++dberr_t
++wsrep_append_foreign_key(
++/*===========================*/
++      trx_t*          trx,            /*!< in: trx */
++      dict_foreign_t* foreign,        /*!< in: foreign key constraint */
++      const rec_t*    rec,            /*!<in: clustered index record */
++      dict_index_t*   index,          /*!<in: clustered index */
++      ibool           referenced,     /*!<in: is check for referenced table */
++      ibool           shared)         /*!<in: is shared access */
++{
++      THD*    thd             = (THD*)trx->mysql_thd;
++      int rcode               = 0;
++      char    cache_key[513]  = {'\0'};
++      int   cache_key_len;
++      bool const copy = true;
++      ut_a(trx);
++      if (!wsrep_on(trx->mysql_thd) ||
++          wsrep_thd_exec_mode(thd) != LOCAL_STATE)
++              return DB_SUCCESS;
++
++      if (!thd || !foreign ||
++          (!foreign->referenced_table && !foreign->foreign_table))
++      {
++              WSREP_INFO("FK: %s missing in: %s",
++                      (!thd)      ?  "thread"     :
++                      ((!foreign) ?  "constraint" :
++                      ((!foreign->referenced_table) ?
++                           "referenced table" : "foreign table")),
++                         (thd && wsrep_thd_query(thd)) ?
++                         wsrep_thd_query(thd) : "void");
++              return DB_ERROR;
++      }
++
++      if ( !((referenced) ?
++              foreign->referenced_table : foreign->foreign_table))
++      {
++              WSREP_DEBUG("pulling %s table into cache",
++                          (referenced) ? "referenced" : "foreign");
++              mutex_enter(&(dict_sys->mutex));
++              if (referenced)
++              {
++                      foreign->referenced_table =
++                              dict_table_get_low(
++                                      foreign->referenced_table_name_lookup);
++                      if (foreign->referenced_table)
++                      {
++                              foreign->referenced_index =
++                                      wsrep_dict_foreign_find_index(
++                                              foreign->referenced_table, NULL,
++                                              foreign->referenced_col_names,
++                                              foreign->n_fields, 
++                                              foreign->foreign_index,
++                                              TRUE, FALSE);
++                      }
++              }
++              else
++              {
++                      foreign->foreign_table =
++                              dict_table_get_low(
++                                      foreign->foreign_table_name_lookup);
++                      if (foreign->foreign_table)
++                      {
++                              foreign->foreign_index =
++                                      wsrep_dict_foreign_find_index(
++                                              foreign->foreign_table, NULL,
++                                              foreign->foreign_col_names,
++                                              foreign->n_fields,
++                                              foreign->referenced_index, 
++                                              TRUE, FALSE);
++                      }
++              }
++              mutex_exit(&(dict_sys->mutex));
++      }
++
++      if ( !((referenced) ?
++              foreign->referenced_table : foreign->foreign_table))
++      {
++              WSREP_WARN("FK: %s missing in query: %s",
++                         (!foreign->referenced_table) ?
++                         "referenced table" : "foreign table",
++                         (wsrep_thd_query(thd)) ?
++                         wsrep_thd_query(thd) : "void");
++              return DB_ERROR;
++      }
++      byte  key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
++      ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH;
++
++      dict_index_t *idx_target = (referenced) ?
++              foreign->referenced_index : index;
++      dict_index_t *idx = (referenced) ?
++              UT_LIST_GET_FIRST(foreign->referenced_table->indexes) :
++              UT_LIST_GET_FIRST(foreign->foreign_table->indexes);
++      int i = 0;
++      while (idx != NULL && idx != idx_target) {
++              if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) {
++                      i++;
++              }
++              idx = UT_LIST_GET_NEXT(indexes, idx);
++      }
++      ut_a(idx);
++      key[0] = (char)i;
++
++      rcode = wsrep_rec_get_foreign_key(
++              &key[1], &len, rec, index, idx,
++              wsrep_protocol_version > 1);
++      if (rcode != DB_SUCCESS) {
++              WSREP_ERROR(
++                      "FK key set failed: %d (%lu %lu), index: %s %s, %s",
++                      rcode, referenced, shared,
++                      (index && index->name)       ? index->name :
++                              "void index",
++                      (index && index->table_name) ? index->table_name :
++                              "void table",
++                      wsrep_thd_query(thd));
++              return DB_ERROR;
++      }
++      strncpy(cache_key,
++              (wsrep_protocol_version > 1) ?
++              ((referenced) ?
++                      foreign->referenced_table->name :
++                      foreign->foreign_table->name) :
++              foreign->foreign_table->name, sizeof(cache_key) - 1);
++      cache_key_len = strlen(cache_key);
++// #define WSREP_DEBUG_PRINT
++#ifdef WSREP_DEBUG_PRINT
++      ulint j;
++      fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
++              cache_key, (shared) ? "shared" : "exclusive", len+1);
++      for (j=0; j<len+1; j++) {
++              fprintf(stderr, " %hhX, ", key[j]);
++      }
++      fprintf(stderr, "\n");
++#endif
++      char *p = strchr(cache_key, '/');
++      if (p) {
++              *p = '\0';
++      } else {
++              WSREP_WARN("unexpected foreign key table %s %s",
++                         foreign->referenced_table->name,
++                         foreign->foreign_table->name);
++      }
++
++      wsrep_buf_t wkey_part[3];
++        wsrep_key_t wkey = {wkey_part, 3};
++      if (!wsrep_prepare_key_for_innodb(
++              (const uchar*)cache_key,
++              cache_key_len +  1,
++              (const uchar*)key, len+1,
++              wkey_part,
++              &wkey.key_parts_num)) {
++              WSREP_WARN("key prepare failed for cascaded FK: %s",
++                         (wsrep_thd_query(thd)) ?
++                          wsrep_thd_query(thd) : "void");
++              return DB_ERROR;
++      }
++      rcode = wsrep->append_key(
++              wsrep,
++              wsrep_ws_handle(thd, trx),
++              &wkey,
++              1,
++              shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
++              copy);
++      if (rcode) {
++              DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
++              WSREP_ERROR("Appending cascaded fk row key failed: %s, %d",
++                          (wsrep_thd_query(thd)) ?
++                           wsrep_thd_query(thd) : "void", rcode);
++              return DB_ERROR;
++      }
++
++      return DB_SUCCESS;
++}
++
++static int
++wsrep_append_key(
++/*==================*/
++      THD             *thd,
++      trx_t           *trx,
++      TABLE_SHARE     *table_share,
++      TABLE           *table,
++      const char*     key,
++      uint16_t        key_len,
++      bool            shared
++)
++{
++      DBUG_ENTER("wsrep_append_key");
++      bool const copy = true;
++#ifdef WSREP_DEBUG_PRINT
++      fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s\n SQL: %s ",
++              (shared) ? "Shared" : "Exclusive",
++              wsrep_thd_thread_id(thd), (long long)trx->id, key_len,
++              table_share->table_name.str, wsrep_thd_query(thd));
++      for (int i=0; i<key_len; i++) {
++              fprintf(stderr, "%hhX, ", key[i]);
++      }
++      fprintf(stderr, "\n");
++#endif
++      wsrep_buf_t wkey_part[3];
++      wsrep_key_t wkey = {wkey_part, 3};
++      if (!wsrep_prepare_key_for_innodb(
++                      (const uchar*)table_share->table_cache_key.str,
++                      table_share->table_cache_key.length,
++                      (const uchar*)key, key_len,
++                      wkey_part,
++                      &wkey.key_parts_num)) {
++              WSREP_WARN("key prepare failed for: %s",
++                         (wsrep_thd_query(thd)) ?
++                         wsrep_thd_query(thd) : "void");
++              DBUG_RETURN(-1);
++      }
++
++      int rcode = wsrep->append_key(
++                              wsrep,
++                              wsrep_ws_handle(thd, trx),
++                              &wkey,
++                              1,
++                              shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
++                              copy);
++      if (rcode) {
++              DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
++              WSREP_WARN("Appending row key failed: %s, %d",
++                         (wsrep_thd_query(thd)) ?
++                         wsrep_thd_query(thd) : "void", rcode);
++              DBUG_RETURN(-1);
++      }
++      DBUG_RETURN(0);
++}
++
++extern void compute_md5_hash(char *digest, const char *buf, int len);
++#define MD5_HASH compute_md5_hash
++
++int
++ha_innobase::wsrep_append_keys(
++/*==================*/
++      THD             *thd,
++      bool            shared,
++      const uchar*    record0,        /* in: row in MySQL format */
++      const uchar*    record1)        /* in: row in MySQL format */
++{
++      int rcode;
++      DBUG_ENTER("wsrep_append_keys");
++
++      bool key_appended = false;
++      trx_t *trx = thd_to_trx(thd);
++
++      if (table_share && table_share->tmp_table  != NO_TMP_TABLE) {
++              WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", 
++                          wsrep_thd_thread_id(thd),
++                          table_share->tmp_table,
++                          (wsrep_thd_query(thd)) ? 
++                          wsrep_thd_query(thd) : "void");
++              DBUG_RETURN(0);
++      }
++
++      if (wsrep_protocol_version == 0) {
++              uint    len;
++              char    keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
++              char    *key            = &keyval[0];
++              ibool    is_null;
++
++              len = wsrep_store_key_val_for_row(
++                      thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, 
++                      record0, &is_null);
++
++              if (!is_null) {
++                      rcode = wsrep_append_key(
++                              thd, trx, table_share, table, keyval, 
++                              len, shared);
++                      if (rcode) DBUG_RETURN(rcode);
++              }
++              else
++              {
++                      WSREP_DEBUG("NULL key skipped (proto 0): %s", 
++                                  wsrep_thd_query(thd));
++              }
++      } else {
++              ut_a(table->s->keys <= 256);
++              uint i;
++              bool hasPK= false;
++
++              for (i=0; i<table->s->keys; ++i) {
++                      KEY*  key_info  = table->key_info + i;
++                      if (key_info->flags & HA_NOSAME) {
++                              hasPK = true;
++                      }
++              }
++
++              for (i=0; i<table->s->keys; ++i) {
++                      uint  len;
++                      char  keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
++                      char  keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
++                      char* key0              = &keyval0[1];
++                      char* key1              = &keyval1[1];
++                      KEY*  key_info  = table->key_info + i;
++                      ibool is_null;
++
++                      dict_index_t* idx  = innobase_get_index(i);
++                      dict_table_t* tab  = (idx) ? idx->table : NULL;
++
++                      keyval0[0] = (char)i;
++                      keyval1[0] = (char)i;
++
++                      if (!tab) {
++                              WSREP_WARN("MySQL-InnoDB key mismatch %s %s",
++                                         table->s->table_name.str, 
++                                         key_info->name);
++                      }
++                      /* !hasPK == table with no PK, must append all non-unique keys */
++                      if (!hasPK || key_info->flags & HA_NOSAME ||
++                          ((tab &&
++                            dict_table_get_referenced_constraint(tab, idx)) ||
++                           (!tab && referenced_by_foreign_key()))) {
++
++                              len = wsrep_store_key_val_for_row(
++                                      thd, table, i, key0, 
++                                      WSREP_MAX_SUPPORTED_KEY_LENGTH, 
++                                      record0, &is_null);
++                              if (!is_null) {
++                                      rcode = wsrep_append_key(
++                                              thd, trx, table_share, table, 
++                                              keyval0, len+1, shared);
++                                      if (rcode) DBUG_RETURN(rcode);
++
++                                      if (key_info->flags & HA_NOSAME || shared)
++                                              key_appended = true;
++                              }
++                              else
++                              {
++                                      WSREP_DEBUG("NULL key skipped: %s", 
++                                                  wsrep_thd_query(thd));
++                              }
++                              if (record1) {
++                                      len = wsrep_store_key_val_for_row(
++                                              thd, table, i, key1, 
++                                              WSREP_MAX_SUPPORTED_KEY_LENGTH,
++                                              record1, &is_null);
++                                      if (!is_null && memcmp(key0, key1, len)) {
++                                              rcode = wsrep_append_key(
++                                                      thd, trx, table_share, 
++                                                      table, 
++                                                      keyval1, len+1, shared);
++                                              if (rcode) DBUG_RETURN(rcode);
++                                      }
++                              }
++                      }
++              }
++      }
++
++      /* if no PK, calculate hash of full row, to be the key value */
++      if (!key_appended && wsrep_certify_nonPK) {
++              uchar digest[16];
++              int rcode;
++
++              wsrep_calc_row_hash(digest, record0, table, prebuilt, thd);
++              if ((rcode = wsrep_append_key(thd, trx, table_share, table, 
++                                            (const char*) digest, 16, 
++                                            shared))) {
++                      DBUG_RETURN(rcode);
++              }
++
++              if (record1) {
++                      wsrep_calc_row_hash(
++                              digest, record1, table, prebuilt, thd);
++                      if ((rcode = wsrep_append_key(thd, trx, table_share, 
++                                                    table,
++                                                    (const char*) digest, 
++                                                    16, shared))) {
++                              DBUG_RETURN(rcode);
++                      }
++              }
++              DBUG_RETURN(0);
++      }
++
++      DBUG_RETURN(0);
++}
++#endif
+ /*********************************************************************//**
+ Stores a reference to the current row to 'ref' field of the handle. Note
+ that in the case where we have generated the clustered index for the
+@@ -12128,11 +13225,18 @@ ha_innobase::external_lock(
+               /* used by test case */
+               DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;);
+               if (!skip) {
++#ifdef WITH_WSREP
++                if (!wsrep_on(thd) || wsrep_thd_exec_mode(thd) == LOCAL_STATE)
++                      {
++#endif /* WITH_WSREP */
+                       my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0),
+                                " InnoDB is limited to row-logging when "
+                                "transaction isolation level is "
+                                "READ COMMITTED or READ UNCOMMITTED.");
+                       DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE);
++#ifdef WITH_WSREP
++                      }
++#endif /* WITH_WSREP */
+               }
+       }
+@@ -12163,6 +13267,33 @@ ha_innobase::external_lock(
+       }
++      /* Check for UPDATEs in read-only mode. */
++      if (srv_read_only_mode
++          && (thd_sql_command(thd) == SQLCOM_UPDATE
++              || thd_sql_command(thd) == SQLCOM_INSERT
++              || thd_sql_command(thd) == SQLCOM_REPLACE
++              || thd_sql_command(thd) == SQLCOM_DROP_TABLE
++              || thd_sql_command(thd) == SQLCOM_ALTER_TABLE
++              || thd_sql_command(thd) == SQLCOM_OPTIMIZE
++              || (thd_sql_command(thd) == SQLCOM_CREATE_TABLE
++                  && lock_type == F_WRLCK)
++              || thd_sql_command(thd) == SQLCOM_CREATE_INDEX
++              || thd_sql_command(thd) == SQLCOM_DROP_INDEX
++              || thd_sql_command(thd) == SQLCOM_DELETE)) {
++
++              if (thd_sql_command(thd) == SQLCOM_CREATE_TABLE)
++              {
++                      ib_senderrf(thd, IB_LOG_LEVEL_WARN,
++                                  ER_INNODB_READ_ONLY);
++                      DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
++              } else {
++                      ib_senderrf(thd, IB_LOG_LEVEL_WARN,
++                                  ER_READ_ONLY_MODE);
++                      DBUG_RETURN(HA_ERR_TABLE_READONLY);
++              }
++
++      }
++
+       trx = prebuilt->trx;
+       prebuilt->sql_stat_start = TRUE;
+@@ -13218,8 +14349,20 @@ ha_innobase::get_auto_increment(
+               next value in the series. */
+               if (prebuilt->autoinc_increment > increment) {
++#ifdef WITH_WSREP
++                      WSREP_DEBUG("autoinc decrease: %llu -> %llu\n"
++                                  "THD: %ld, current: %llu, autoinc: %llu", 
++                                  prebuilt->autoinc_increment,
++                                  increment,
++                                  wsrep_thd_thread_id(ha_thd()),
++                                  current, autoinc);
++                      if (!wsrep_on(ha_thd()))
++                      {
++#endif /* WITH_WSREP */
+                       current = autoinc - prebuilt->autoinc_increment;
+-
++#ifdef WITH_WSREP
++                      }
++#endif /* WITH_WSREP */
+                       current = innobase_next_autoinc(
+                               current, 1, increment, 1, col_max_value);
+@@ -13580,6 +14723,9 @@ innobase_xa_prepare(
+       to the session variable take effect only in the next transaction */
+       if (!trx->support_xa) {
++#ifdef WITH_WSREP
++                thd_get_xid(thd, (MYSQL_XID*) &trx->xid);
++#endif // WITH_WSREP
+               return(0);
+       }
+@@ -15648,6 +16794,292 @@ static SHOW_VAR innodb_status_variables_export[]= {
+ static struct st_mysql_storage_engine innobase_storage_engine=
+ { MYSQL_HANDLERTON_INTERFACE_VERSION };
++#ifdef WITH_WSREP
++void
++wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno)
++{
++      WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be "
++              "caused by:\n\t"
++              "1) unsupported configuration options combination, please check documentation.\n\t"
++              "2) a bug in the code.\n\t"
++              "3) a database corruption.\n Node consistency compromized, "
++              "need to abort. Restart the node to resync with cluster.",
++              (long long)bf_seqno, (long long)victim_seqno);
++      abort();
++}
++
++int
++wsrep_innobase_kill_one_trx(void * const bf_thd_ptr,
++                            const trx_t * const bf_trx,
++                            trx_t *victim_trx, ibool signal)
++{
++        ut_ad(lock_mutex_own());
++        ut_ad(trx_mutex_own(victim_trx));
++        ut_ad(bf_thd_ptr);
++        ut_ad(victim_trx);
++
++      DBUG_ENTER("wsrep_innobase_kill_one_trx");
++        THD *bf_thd       = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL;
++      THD *thd          = (THD *) victim_trx->mysql_thd;
++      int64_t bf_seqno  = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0;
++
++      if (!thd) {
++              DBUG_PRINT("wsrep", ("no thd for conflicting lock"));
++              WSREP_WARN("no THD for trx: %llu", (long long)victim_trx->id);
++              DBUG_RETURN(1);
++      }
++      if (!bf_thd) {
++              DBUG_PRINT("wsrep", ("no BF thd for conflicting lock"));
++              WSREP_WARN("no BF THD for trx: %llu",
++                         (bf_trx) ? (long long)bf_trx->id : 0);
++              DBUG_RETURN(1);
++      }
++
++      WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
++
++      WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%llu) trx: %llu",
++                  signal, (long long)bf_seqno,
++                  (long long)wsrep_thd_thread_id(thd),
++                  (long long)victim_trx->id);
++
++      WSREP_DEBUG("Aborting query: %s", 
++                (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void");
++
++      wsrep_thd_LOCK(thd);
++
++      if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
++              WSREP_DEBUG("kill trx EXITING for %llu",
++                          (long long)victim_trx->id);
++              wsrep_thd_UNLOCK(thd);
++              DBUG_RETURN(0);
++      }
++      if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
++              WSREP_DEBUG("withdraw for BF trx: %llu, state: %d",
++                          (long long)victim_trx->id,
++              wsrep_thd_conflict_state(thd));
++      }
++
++      switch (wsrep_thd_conflict_state(thd)) {
++      case NO_CONFLICT: 
++              wsrep_thd_set_conflict_state(thd, MUST_ABORT);
++              break;
++        case MUST_ABORT:
++              WSREP_DEBUG("victim %llu in MUST ABORT state",
++                          (long long)victim_trx->id);
++              wsrep_thd_UNLOCK(thd);
++              wsrep_thd_awake(thd, signal);
++              DBUG_RETURN(0);
++              break;
++      case ABORTED:
++      case ABORTING: // fall through
++      default:
++              WSREP_DEBUG("victim %llu in state %d",
++                          (long long)victim_trx->id,
++                          wsrep_thd_conflict_state(thd));
++              wsrep_thd_UNLOCK(thd);
++              DBUG_RETURN(0);
++              break;
++      }
++
++      switch (wsrep_thd_query_state(thd)) {
++      case QUERY_COMMITTING:
++              enum wsrep_status rcode;
++
++              WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu", 
++                          (long long)victim_trx->id);
++              wsrep_thd_awake(thd, signal); 
++
++              if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
++                      wsrep_abort_slave_trx(bf_seqno,
++                                            wsrep_thd_trx_seqno(thd));
++              } else {
++                      rcode = wsrep->abort_pre_commit(
++                              wsrep, bf_seqno,
++                              (wsrep_trx_id_t)victim_trx->id
++                      );
++                      
++                      switch (rcode) {
++                      case WSREP_WARNING:
++                              WSREP_DEBUG("cancel commit warning: %llu",
++                                          (long long)victim_trx->id);
++                              wsrep_thd_UNLOCK(thd);
++                              DBUG_RETURN(1);
++                              break;
++                      case WSREP_OK:
++                              break;
++                      default:
++                              WSREP_ERROR(
++                                      "cancel commit bad exit: %d %llu", 
++                                      rcode, 
++                                      (long long)victim_trx->id);
++                              /* unable to interrupt, must abort */
++                              /* note: kill_mysql() will block, if we cannot.
++                               * kill the lock holder first.
++                               */
++                              abort();
++                              break;
++                      }
++              }
++              break;
++      case QUERY_EXEC:
++              /* it is possible that victim trx is itself waiting for some 
++               * other lock. We need to cancel this waiting
++               */
++              WSREP_DEBUG("kill trx QUERY_EXEC for %llu", (long long)victim_trx->id);
++
++              victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
++              if (victim_trx->lock.wait_lock) {
++                      WSREP_DEBUG("victim has wait flag: %ld",
++                              wsrep_thd_thread_id(thd));
++                      lock_t*  wait_lock = victim_trx->lock.wait_lock;
++                      if (wait_lock) {
++                              WSREP_DEBUG("canceling wait lock");
++                              victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
++                              lock_cancel_waiting_and_release(wait_lock);
++                      }
++
++                      wsrep_thd_awake(thd, signal); 
++              } else {
++                      /* abort currently executing query */
++                      DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", 
++                                            wsrep_thd_thread_id(thd)));
++                      WSREP_DEBUG("kill query for: %ld",
++                              wsrep_thd_thread_id(thd));
++                      wsrep_thd_awake(thd, signal); 
++
++                      /* for BF thd, we need to prevent him from committing */
++                      if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
++                              wsrep_abort_slave_trx(bf_seqno,
++                                                  wsrep_thd_trx_seqno(thd));
++                      }
++              }
++              break;
++      case QUERY_IDLE:
++      {
++              bool skip_abort= false;
++              wsrep_aborting_thd_t abortees;
++
++              WSREP_DEBUG("kill IDLE for %llu", (long long)victim_trx->id);
++
++              if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
++                      WSREP_DEBUG("kill BF IDLE, seqno: %lld",
++                                  (long long)wsrep_thd_trx_seqno(thd));
++                      wsrep_thd_UNLOCK(thd);
++                      wsrep_abort_slave_trx(bf_seqno,
++                                            wsrep_thd_trx_seqno(thd));
++                      DBUG_RETURN(0);
++              }
++                /* This will lock thd from proceeding after net_read() */
++              wsrep_thd_set_conflict_state(thd, ABORTING);
++
++              mysql_mutex_lock(&LOCK_wsrep_rollback);
++
++              abortees = wsrep_aborting_thd;
++              while (abortees && !skip_abort) {
++                      /* check if we have a kill message for this already */
++                      if (abortees->aborting_thd == thd) {
++                              skip_abort = true;
++                              WSREP_WARN("duplicate thd aborter %lu", 
++                                        wsrep_thd_thread_id(thd));
++                      }
++                      abortees = abortees->next;
++              }
++              if (!skip_abort) {
++                      wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t)
++                              my_malloc(sizeof(struct wsrep_aborting_thd), 
++                                        MYF(0));
++                      aborting->aborting_thd  = thd;
++                      aborting->next          = wsrep_aborting_thd;
++                      wsrep_aborting_thd      = aborting;
++                      DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
++                                             wsrep_thd_thread_id(thd)));
++                      WSREP_DEBUG("enqueuing trx abort for (%lu)",
++                                  wsrep_thd_thread_id(thd));
++              }
++
++              DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
++              WSREP_DEBUG("signaling aborter");
++              mysql_cond_signal(&COND_wsrep_rollback);
++              mysql_mutex_unlock(&LOCK_wsrep_rollback);
++
++              break;
++      }
++      default:
++              WSREP_WARN("bad wsrep query state: %d", 
++                        wsrep_thd_query_state(thd));
++              break;
++      }
++      wsrep_thd_UNLOCK(thd);
++     
++      DBUG_RETURN(0);
++}
++static int 
++wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, 
++                      my_bool signal)
++{
++      DBUG_ENTER("wsrep_innobase_abort_thd");
++      trx_t* victim_trx = thd_to_trx(victim_thd);
++      trx_t* bf_trx     = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
++      WSREP_DEBUG("abort transaction: BF: %s victim: %s", 
++                  wsrep_thd_query(bf_thd),
++                  wsrep_thd_query(victim_thd));
++
++      if (victim_trx)
++      {
++                lock_mutex_enter();
++                trx_mutex_enter(victim_trx);
++              int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
++                                                        victim_trx, signal);
++                trx_mutex_exit(victim_trx);
++                lock_mutex_exit();
++              wsrep_srv_conc_cancel_wait(victim_trx);
++
++              DBUG_RETURN(rcode);
++      } else {
++              WSREP_DEBUG("victim does not have transaction");
++              wsrep_thd_LOCK(victim_thd);
++              wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT);
++              wsrep_thd_UNLOCK(victim_thd);
++              wsrep_thd_awake(victim_thd, signal); 
++      }
++      DBUG_RETURN(-1);
++}
++
++static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid)
++{
++      DBUG_ASSERT(hton == innodb_hton_ptr);
++        if (wsrep_is_wsrep_xid(xid)) {
++                mtr_t mtr;
++                mtr_start(&mtr);
++                trx_sysf_t* sys_header = trx_sysf_get(&mtr);
++                trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
++                mtr_commit(&mtr);
++                innobase_flush_logs(hton);
++                return 0;
++        } else {
++                return 1;
++        }
++}
++
++static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid)
++{
++      DBUG_ASSERT(hton == innodb_hton_ptr);
++        trx_sys_read_wsrep_checkpoint(xid);
++        return 0;
++}
++
++static void
++wsrep_fake_trx_id(
++/*==================*/
++      handlerton      *hton,
++      THD             *thd)   /*!< in: user thread handle */
++{
++      trx_id_t trx_id = trx_sys_get_new_trx_id();
++
++      (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
++}
++
++#endif /* WITH_WSREP */
+ /* plugin options */
+ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm,
+@@ -16359,6 +17791,40 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge,
+   NULL, NULL, FALSE);
+ #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
++#ifdef WITH_INNODB_DISALLOW_WRITES
++/*******************************************************
++ *    innobase_disallow_writes variable definition     *
++ *******************************************************/
++ 
++/* Must always init to FALSE. */
++static my_bool        innobase_disallow_writes        = FALSE;
++
++/**************************************************************************
++An "update" method for innobase_disallow_writes variable. */
++static
++void
++innobase_disallow_writes_update(
++/*============================*/
++      THD*                    thd,            /* in: thread handle */
++      st_mysql_sys_var*       var,            /* in: pointer to system
++                                              variable */
++      void*                   var_ptr,        /* out: pointer to dynamic
++                                              variable */
++      const void*             save)           /* in: temporary storage */
++{
++      *(my_bool*)var_ptr = *(my_bool*)save;
++      ut_a(srv_allow_writes_event);
++      if (*(my_bool*)var_ptr)
++              os_event_reset(srv_allow_writes_event);
++      else
++              os_event_set(srv_allow_writes_event);
++}
++
++static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes,
++  PLUGIN_VAR_NOCMDOPT,
++  "Tell InnoDB to stop any writes to disk",
++  NULL, innobase_disallow_writes_update, FALSE);
++#endif /* WITH_INNODB_DISALLOW_WRITES */
+ static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead,
+   PLUGIN_VAR_NOCMDARG,
+   "Whether to use read ahead for random access within an extent.",
+@@ -16577,6 +18043,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
+   MYSQL_SYSVAR(change_buffering_debug),
+   MYSQL_SYSVAR(disable_background_merge),
+ #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
++#ifdef WITH_INNODB_DISALLOW_WRITES
++  MYSQL_SYSVAR(disallow_writes),
++#endif /* WITH_INNODB_DISALLOW_WRITES */
+   MYSQL_SYSVAR(random_read_ahead),
+   MYSQL_SYSVAR(read_ahead_threshold),
+   MYSQL_SYSVAR(read_only),
+diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
+index f735b6f..45b8fd3 100644
+--- a/storage/innobase/handler/ha_innodb.h
++++ b/storage/innobase/handler/ha_innodb.h
+@@ -95,6 +95,10 @@ class ha_innobase: public handler
+       void innobase_initialize_autoinc();
+       dict_index_t* innobase_get_index(uint keynr);
++#ifdef WITH_WSREP
++      int wsrep_append_keys(THD *thd, bool shared,
++                                const uchar* record0, const uchar* record1);
++#endif
+       /* Init values for the class: */
+  public:
+       ha_innobase(handlerton *hton, TABLE_SHARE *table_arg);
+@@ -440,6 +444,38 @@ bool thd_is_strict_mode(const MYSQL_THD thd)
+ __attribute__((nonnull));
+ } /* extern "C" */
++#ifdef WITH_WSREP
++#include <wsrep_mysqld.h>
++extern "C" bool wsrep_thd_is_wsrep_on(THD *thd);
++
++extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
++extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd);
++extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd);
++extern "C" const char * wsrep_thd_exec_mode_str(THD *thd);
++extern "C" const char * wsrep_thd_conflict_state_str(THD *thd);
++extern "C" const char * wsrep_thd_query_state_str(THD *thd);
++extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
++
++extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
++extern "C" void wsrep_thd_set_query_state(
++      THD *thd, enum wsrep_query_state state);
++extern "C" void wsrep_thd_set_conflict_state(
++      THD *thd, enum wsrep_conflict_state state);
++
++extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id);
++
++extern "C"void wsrep_thd_LOCK(THD *thd);
++extern "C"void wsrep_thd_UNLOCK(THD *thd);
++extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
++extern "C" time_t wsrep_thd_query_start(THD *thd);
++extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
++extern "C" int64_t wsrep_thd_trx_seqno(THD *thd);
++extern "C" query_id_t wsrep_thd_query_id(THD *thd);
++extern "C" char * wsrep_thd_query(THD *thd);
++extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd);
++extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id);
++extern "C" void wsrep_thd_awake(THD *thd, my_bool signal);
++#endif
+ struct trx_t;
+ extern const struct _ft_vft ft_vft_result;
+diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
+index 19812ce..4f2c8d4 100644
+--- a/storage/innobase/handler/handler0alter.cc
++++ b/storage/innobase/handler/handler0alter.cc
+@@ -46,6 +46,10 @@ Smart ALTER TABLE
+ #include "srv0mon.h"
+ #include "fts0priv.h"
+ #include "pars0pars.h"
++#ifdef WITH_WSREP
++//#include "wsrep_api.h"
++#include <sql_acl.h>  // PROCESS_ACL
++#endif
+ #include "row0sel.h"
+ #include "ha_innodb.h"
+diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
+index 460a7e1..5b9f052 100644
+--- a/storage/innobase/include/dict0mem.h
++++ b/storage/innobase/include/dict0mem.h
+@@ -484,6 +484,9 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */
+ /** Defines the maximum fixed length column size */
+ #define DICT_MAX_FIXED_COL_LEN                DICT_ANTELOPE_MAX_INDEX_COL_LEN
++#ifdef WITH_WSREP
++#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500
++#endif /* WITH_WSREP */
+ /** Data structure for a field in an index */
+ struct dict_field_t{
+@@ -767,6 +770,23 @@ struct dict_foreign_with_index {
+       const dict_index_t*     m_index;
+ };
++#ifdef WITH_WSREP
++/** A function object to find a foreign key with the given index as the
++foreign index. Return the foreign key with matching criteria or NULL */
++struct dict_foreign_with_foreign_index {
++
++      dict_foreign_with_foreign_index(const dict_index_t*     index)
++      : m_index(index)
++      {}
++
++      bool operator()(const dict_foreign_t*   foreign) const
++      {
++              return(foreign->foreign_index == m_index);
++      }
++
++      const dict_index_t*     m_index;
++};
++#endif
+ /* A function object to check if the foreign constraint is between different
+ tables.  Returns true if foreign key constraint is between different tables,
+ false otherwise. */
+diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
+index fa202aa..330bd3b 100644
+--- a/storage/innobase/include/ha_prototypes.h
++++ b/storage/innobase/include/ha_prototypes.h
+@@ -273,6 +273,23 @@ innobase_casedn_str(
+ /*================*/
+       char*   a);     /*!< in/out: string to put in lower case */
++#ifdef WITH_WSREP
++UNIV_INTERN
++int
++wsrep_innobase_kill_one_trx(void *thd_ptr,
++                            const trx_t *bf_trx, trx_t *victim_trx, ibool signal);
++my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
++int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync);
++my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
++int wsrep_trx_order_before(void *thd1, void *thd2);
++int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number,
++                            unsigned char* str, unsigned int str_length,
++                            unsigned int buf_length);
++UNIV_INTERN
++int 
++wsrep_on(void *thd_ptr);
++int wsrep_is_wsrep_xid(const void*);
++#endif /* WITH_WSREP */
+ /**********************************************************************//**
+ Determines the connection character set.
+ @return       connection character set */
+diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h
+index 6f9a628..9a4077b 100644
+--- a/storage/innobase/include/hash0hash.h
++++ b/storage/innobase/include/hash0hash.h
+@@ -144,6 +144,33 @@ do {\
+       }\
+ } while (0)
++#ifdef WITH_WSREP
++/*******************************************************************//**
++Inserts a struct to the head of hash table. */
++
++#define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA)   \
++do {                                                  \
++      hash_cell_t*    cell3333;                       \
++      TYPE*           struct3333;                     \
++                                                      \
++      HASH_ASSERT_OWN(TABLE, FOLD)                    \
++                                                      \
++      (DATA)->NAME = NULL;                            \
++                                                      \
++      cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\
++                                                      \
++      if (cell3333->node == NULL) {                   \
++              cell3333->node = DATA;                  \
++              DATA->NAME = NULL;                      \
++      } else {                                        \
++              struct3333 = (TYPE*) cell3333->node;    \
++                                                      \
++              DATA->NAME = struct3333;                \
++                                                      \
++              cell3333->node = DATA;                  \
++      }                                               \
++} while (0)
++#endif /*WITH_WSREP */
+ #ifdef UNIV_HASH_DEBUG
+ # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1)
+ # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1
+diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
+index 6d5ed35..385853b 100644
+--- a/storage/innobase/include/lock0lock.h
++++ b/storage/innobase/include/lock0lock.h
+@@ -972,6 +972,16 @@ extern lock_sys_t*        lock_sys;
+       mutex_exit(&lock_sys->wait_mutex);      \
+ } while (0)
++#ifdef WITH_WSREP
++/*********************************************************************//**
++Cancels a waiting lock request and releases possible other transactions
++waiting behind it. */
++UNIV_INTERN
++void
++lock_cancel_waiting_and_release(
++/*============================*/
++      lock_t* lock);  /*!< in/out: waiting lock request */
++#endif /* WITH_WSREP */
+ #ifndef UNIV_NONINL
+ #include "lock0lock.ic"
+ #endif
+diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
+index 8e7d5ff..5dc4971 100644
+--- a/storage/innobase/include/rem0rec.h
++++ b/storage/innobase/include/rem0rec.h
+@@ -981,6 +981,15 @@ are given in one byte (resp. two byte) format. */
+ two upmost bits in a two byte offset for special purposes */
+ #define REC_MAX_DATA_SIZE     (16 * 1024)
++#ifdef WITH_WSREP
++dberr_t wsrep_rec_get_foreign_key(
++      byte            *buf,     /* out: extracted key */
++      ulint           *buf_len, /* in/out: length of buf */
++      const rec_t*    rec,      /* in: physical record */
++      dict_index_t*   index_for,  /* in: index for foreign table */
++      dict_index_t*   index_ref,  /* in: index for referenced table */
++      ibool           new_protocol); /* in: protocol > 1 */
++#endif /* WITH_WSREP */
+ #ifndef UNIV_NONINL
+ #include "rem0rec.ic"
+ #endif
+diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
+index 7a6c9f9..4b40c36 100644
+--- a/storage/innobase/include/srv0srv.h
++++ b/storage/innobase/include/srv0srv.h
+@@ -257,6 +257,10 @@ extern ulong      srv_flush_log_at_trx_commit;
+ extern uint   srv_flush_log_at_timeout;
+ extern char   srv_adaptive_flushing;
++#ifdef WITH_INNODB_DISALLOW_WRITES
++/* When this event is reset we do not allow any file writes to take place. */
++extern os_event_t     srv_allow_writes_event;
++#endif /* WITH_INNODB_DISALLOW_WRITES */
+ /* If this flag is TRUE, then we will load the indexes' (and tables') metadata
+ even if they are marked as "corrupted". Mostly it is for DBA to process
+ corrupted index and table */
+@@ -884,5 +888,13 @@ struct srv_slot_t{
+ # define srv_start_raw_disk_in_use            0
+ # define srv_file_per_table                   1
+ #endif /* !UNIV_HOTBACKUP */
++#ifdef WITH_WSREP
++UNIV_INTERN
++void
++wsrep_srv_conc_cancel_wait(
++/*==================*/
++      trx_t*  trx);   /*!< in: transaction object associated with the
++                      thread */
++#endif /* WITH_WSREP */
+ #endif
+diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic
+index 616e53d..2a85d2b 100644
+--- a/storage/innobase/include/sync0sync.ic
++++ b/storage/innobase/include/sync0sync.ic
+@@ -213,8 +213,10 @@ mutex_enter_func(
+       ulint           line)           /*!< in: line where locked */
+ {
+       ut_ad(mutex_validate(mutex));
++#ifndef WITH_WSREP
++      /* this cannot be be granted when BF trx kills a trx in lock wait state */
+       ut_ad(!mutex_own(mutex));
+-
++#endif /* WITH_WSREP */
+       /* Note that we do not peek at the value of lock_word before trying
+       the atomic test_and_set; we could peek, and possibly save time. */
+diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
+index 70f214d..28ed5bf 100644
+--- a/storage/innobase/include/trx0sys.h
++++ b/storage/innobase/include/trx0sys.h
+@@ -41,6 +41,9 @@ Created 3/26/1996 Heikki Tuuri
+ #include "ut0bh.h"
+ #include "read0types.h"
+ #include "page0types.h"
++#ifdef WITH_WSREP
++#include "trx0xa.h"
++#endif /* WITH_WSREP */
+ #include "ut0bh.h"
+ typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t;
+@@ -293,6 +296,9 @@ trx_sys_update_mysql_binlog_offset(
+       ib_int64_t      offset, /*!< in: position in that log file */
+       ulint           field,  /*!< in: offset of the MySQL log info field in
+                               the trx sys header */
++#ifdef WITH_WSREP
++        trx_sysf_t*     sys_header, /*!< in: trx sys header */
++#endif /* WITH_WSREP */
+       mtr_t*          mtr);   /*!< in: mtr */
+ /*****************************************************************//**
+ Prints to stderr the MySQL binlog offset info in the trx system header if
+@@ -301,6 +307,19 @@ UNIV_INTERN
+ void
+ trx_sys_print_mysql_binlog_offset(void);
+ /*===================================*/
++#ifdef WITH_WSREP
++/** Update WSREP checkpoint XID in sys header. */
++void
++trx_sys_update_wsrep_checkpoint(
++        const XID*      xid,         /*!< in: WSREP XID */
++        trx_sysf_t*     sys_header,  /*!< in: sys_header */
++        mtr_t*          mtr);        /*!< in: mtr       */
++
++void
++/** Read WSREP checkpoint XID from sys header. */
++trx_sys_read_wsrep_checkpoint(
++        XID* xid); /*!< out: WSREP XID */
++#endif /* WITH_WSREP */
+ /*****************************************************************//**
+ Prints to stderr the MySQL master log offset info in the trx system header if
+ the magic number shows it valid. */
+@@ -529,6 +548,20 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
+                                               within that file */
+ #define TRX_SYS_MYSQL_LOG_NAME                12      /*!< MySQL log file name */
++#ifdef WITH_WSREP
++/* The offset to WSREP XID headers */
++#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500)
++#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0
++#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265
++
++/* XID field: formatID, gtrid_len, bqual_len, xid_data */
++#define TRX_SYS_WSREP_XID_LEN        (4 + 4 + 4 + XIDDATASIZE)
++#define TRX_SYS_WSREP_XID_FORMAT     4
++#define TRX_SYS_WSREP_XID_GTRID_LEN  8
++#define TRX_SYS_WSREP_XID_BQUAL_LEN 12
++#define TRX_SYS_WSREP_XID_DATA      16
++#endif /* WITH_WSREP*/
++
+ /** Doublewrite buffer */
+ /* @{ */
+ /** The offset of the doublewrite buffer header on the trx system header page */
+diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic
+index e097e29..7265a97 100644
+--- a/storage/innobase/include/trx0sys.ic
++++ b/storage/innobase/include/trx0sys.ic
+@@ -445,7 +445,10 @@ trx_id_t
+ trx_sys_get_new_trx_id(void)
+ /*========================*/
+ {
++#ifndef WITH_WSREP
++      /* wsrep_fake_trx_id  violates this assert */
+       ut_ad(mutex_own(&trx_sys->mutex));
++#endif /* WITH_WSREP */
+       /* VERY important: after the database is started, max_trx_id value is
+       divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if
+diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
+index 144e180..6adbe2c 100644
+--- a/storage/innobase/include/trx0trx.h
++++ b/storage/innobase/include/trx0trx.h
+@@ -1004,6 +1004,9 @@ struct trx_t{
+       /*------------------------------*/
+       char detailed_error[256];       /*!< detailed error message for last
+                                       error, or empty. */
++#ifdef WITH_WSREP
++      os_event_t      wsrep_event;    /* event waited for in srv_conc_slot */
++#endif /* WITH_WSREP */
+ };
+ /* Transaction isolation levels (trx->isolation_level) */
+diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
+index bf7ca16..881507a 100644
+--- a/storage/innobase/lock/lock0lock.cc
++++ b/storage/innobase/lock/lock0lock.cc
+@@ -50,6 +50,10 @@ Created 5/7/1996 Heikki Tuuri
+ #include "dict0boot.h"
+ #include <set>
++#ifdef WITH_WSREP
++extern my_bool wsrep_debug;
++extern my_bool wsrep_log_conflicts;
++#endif
+ /* Restricts the length of search we will do in the waits-for
+ graph of transactions */
+ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
+@@ -945,6 +949,9 @@ UNIV_INLINE
+ ibool
+ lock_rec_has_to_wait(
+ /*=================*/
++#ifdef WITH_WSREP
++      ibool           for_locking, /*!< is caller locking or releasing */
++#endif /* WITH_WSREP */
+       const trx_t*    trx,    /*!< in: trx of new lock */
+       ulint           type_mode,/*!< in: precise mode of the new lock
+                               to set: LOCK_S or LOCK_X, possibly
+@@ -1015,9 +1022,59 @@ lock_rec_has_to_wait(
+                       return(FALSE);
+               }
++#ifdef WITH_WSREP
++              /* if BF thread is locking and has conflict with another BF
++                 thread, we need to look at trx ordering and lock types */
++              if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)         &&
++                  wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) {
++
++                      if (wsrep_debug) {
++                              fprintf(stderr, 
++                                      "BF-BF lock conflict, locking: %lu\n",
++                                      for_locking);
++                              lock_rec_print(stderr, lock2);
++                      }
++
++                      if (wsrep_trx_order_before(trx->mysql_thd, 
++                                                 lock2->trx->mysql_thd) &&
++                          (type_mode & LOCK_MODE_MASK) == LOCK_X        &&
++                          (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X)
++                      {
++                              if (for_locking || wsrep_debug) {
++                                      /* exclusive lock conflicts are not
++                                         accepted */
++                                      fprintf(stderr, 
++                                              "BF-BF X lock conflict," 
++                                              "mode: %lu supremum: %lu\n", 
++                                              type_mode, lock_is_on_supremum);
++                                      fprintf(stderr, 
++                                              "conflicts states: my %d locked %d\n", 
++                                              wsrep_thd_conflict_state(trx->mysql_thd, FALSE), 
++                                              wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) );
++                                      lock_rec_print(stderr, lock2);
++                                      if (for_locking) return FALSE;
++                                      //abort();
++                              }
++                      } else {
++                              /* if lock2->index->n_uniq <= 
++                                 lock2->index->n_user_defined_cols
++                                 operation is on uniq index
++                              */
++                              if (wsrep_debug) fprintf(stderr,
++                                      "BF conflict, modes: %lu %lu, "
++                                      "idx: %s-%s n_uniq %u n_user %u\n",
++                                      type_mode, lock2->type_mode,
++                                      lock2->index->name, 
++                                      lock2->index->table_name,
++                                      lock2->index->n_uniq, 
++                                      lock2->index->n_user_defined_cols);
++                              return FALSE;
++                      }
++              }
++#endif /* WITH_WSREP */
+               return(TRUE);
+       }
+-
++      
+       return(FALSE);
+ }
+@@ -1045,7 +1102,11 @@ lock_has_to_wait(
+                       /* If this lock request is for a supremum record
+                       then the second bit on the lock bitmap is set */
++#ifdef WITH_WSREP
++                      return(lock_rec_has_to_wait(FALSE, lock1->trx,
++#else
+                       return(lock_rec_has_to_wait(lock1->trx,
++#endif /* WITH_WSREP */
+                                                   lock1->type_mode, lock2,
+                                                   lock_rec_get_nth_bit(
+                                                           lock1, 1)));
+@@ -1514,6 +1575,11 @@ lock_rec_has_expl(
+       return(NULL);
+ }
++#ifdef WITH_WSREP
++static
++void
++lock_rec_discard(lock_t*      in_lock);
++#endif
+ #ifdef UNIV_DEBUG
+ /*********************************************************************//**
+ Checks if some other transaction has a lock request in the queue.
+@@ -1562,6 +1628,58 @@ lock_rec_other_has_expl_req(
+ }
+ #endif /* UNIV_DEBUG */
++#ifdef WITH_WSREP
++static void 
++wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) {
++        ut_ad(lock_mutex_own());
++        ut_ad(trx_mutex_own(lock->trx));
++      my_bool bf_this  = wsrep_thd_is_BF(trx->mysql_thd, FALSE);
++      my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE);
++
++      if ((bf_this && !bf_other) ||
++              (bf_this && bf_other && wsrep_trx_order_before(
++                      trx->mysql_thd, lock->trx->mysql_thd))) {
++          
++              if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
++                      if (wsrep_debug)
++                              fprintf(stderr, "WSREP: BF victim waiting\n");
++                      /* cannot release lock, until our lock
++                      is in the queue*/
++              } else if (lock->trx != trx) {
++                      if (wsrep_log_conflicts) {
++                              mutex_enter(&trx_sys->mutex);
++                              if (bf_this)
++                                      fputs("\n*** Priority TRANSACTION:\n", 
++                                            stderr);
++                              else
++                                      fputs("\n*** Victim TRANSACTION:\n", 
++                                            stderr);
++                              trx_print_latched(stderr, trx, 3000);
++
++                              if (bf_other)
++                                      fputs("\n*** Priority TRANSACTION:\n", 
++                                            stderr);
++                              else
++                                      fputs("\n*** Victim TRANSACTION:\n", 
++                                            stderr);
++                              trx_print_latched(stderr, lock->trx, 3000);
++
++                              mutex_exit(&trx_sys->mutex);
++                              fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n",
++                                    stderr);
++
++                              if (lock_get_type(lock) == LOCK_REC) {
++                                      lock_rec_print(stderr, lock);
++                              } else {
++                                      lock_table_print(stderr, lock);
++                              }
++                      }
++                      wsrep_innobase_kill_one_trx(trx->mysql_thd,
++                              (const trx_t*) trx, lock->trx, TRUE);
++              }
++      }
++}
++#endif
+ /*********************************************************************//**
+ Checks if some other transaction has a conflicting explicit lock request
+ in the queue, so that we have to wait.
+@@ -1590,7 +1708,14 @@ lock_rec_other_has_conflicting(
+            lock != NULL;
+            lock = lock_rec_get_next_const(heap_no, lock)) {
++#ifdef WITH_WSREP
++              if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) {
++                      trx_mutex_enter(lock->trx);
++                      wsrep_kill_victim(trx, lock);
++                      trx_mutex_exit(lock->trx);
++#else
+               if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) {
++#endif /* WITH_WSREP */
+                       return(lock);
+               }
+       }
+@@ -1683,6 +1808,7 @@ lock_sec_rec_some_has_impl(
+       return(trx_id);
+ }
++#ifndef WITH_WSREP
+ #ifdef UNIV_DEBUG
+ /*********************************************************************//**
+ Checks if some transaction, other than given trx_id, has an explicit
+@@ -1733,6 +1859,7 @@ lock_rec_other_trx_holds_expl(
+       return(holds);
+ }
+ #endif /* UNIV_DEBUG */
++#endif /* !WITH_WSREP */
+ /*********************************************************************//**
+ Return approximate number or record locks (bits set in the bitmap) for
+@@ -1770,6 +1897,27 @@ lock_number_of_rows_locked(
+ }
+ /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/
++#ifdef WITH_WSREP
++static
++void
++wsrep_print_wait_locks(
++/*============*/
++      lock_t*         c_lock) /* conflicting lock to print */
++{
++      if (wsrep_debug &&  c_lock->trx->lock.wait_lock != c_lock) {
++              fprintf(stderr, "WSREP: c_lock != wait lock\n");
++              if (lock_get_type_low(c_lock) & LOCK_TABLE)
++                      lock_table_print(stderr, c_lock);
++              else
++                      lock_rec_print(stderr, c_lock);
++
++              if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE)
++                      lock_table_print(stderr, c_lock->trx->lock.wait_lock);
++              else
++                      lock_rec_print(stderr, c_lock->trx->lock.wait_lock);
++      }
++}
++#endif /* WITH_WSREP */
+ /*********************************************************************//**
+ Creates a new record lock and inserts it to the lock queue. Does NOT check
+@@ -1779,6 +1927,10 @@ static
+ lock_t*
+ lock_rec_create(
+ /*============*/
++#ifdef WITH_WSREP
++      lock_t*           const c_lock, /* conflicting lock */
++      que_thr_t*              thr,
++#endif
+       ulint                   type_mode,/*!< in: lock mode and wait
+                                       flag, type is ignored and
+                                       replaced by LOCK_REC */
+@@ -1850,9 +2002,79 @@ lock_rec_create(
+       ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
++#ifdef WITH_WSREP
++      
++      if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
++              lock_t *hash    = (lock_t *)c_lock->hash;
++              lock_t *prev    = NULL;
++
++              while (hash                                                    &&
++                     wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) &&
++                     wsrep_trx_order_before(
++                              ((lock_t *)hash)->trx->mysql_thd, 
++                              trx->mysql_thd)) {
++                      prev = hash;
++                      hash = (lock_t *)hash->hash;
++              }
++              lock->hash = hash;
++              if (prev) {
++                      prev->hash = lock;
++              } else {
++                      c_lock->hash = lock;
++              }
++              /*
++               * delayed conflict resolution '...kill_one_trx' was not called,
++               * if victim was waiting for some other lock
++               */
++              trx_mutex_enter(c_lock->trx);
++              if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
++
++                      c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE;
++
++                      if (wsrep_debug) wsrep_print_wait_locks(c_lock);
++
++                      trx->lock.que_state = TRX_QUE_LOCK_WAIT;
++                      lock_set_lock_and_trx_wait(lock, trx);
++                      UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock);
++
++                      ut_ad(thr != NULL);
++                      trx->lock.wait_thr = thr;
++                      thr->state = QUE_THR_LOCK_WAIT;
++
++                      /* have to release trx mutex for the duration of
++                         victim lock release. This will eventually call
++                         lock_grant, which wants to grant trx mutex again
++                      */
++                      if (caller_owns_trx_mutex) trx_mutex_exit(trx);
++                      lock_cancel_waiting_and_release(
++                              c_lock->trx->lock.wait_lock);
++                      if (caller_owns_trx_mutex) trx_mutex_enter(trx);
++
++                      /* trx might not wait for c_lock, but some other lock
++                         does not matter if wait_lock was released above
++                       */
++                      if (c_lock->trx->lock.wait_lock == c_lock) {
++                              lock_reset_lock_and_trx_wait(lock);
++                      }
++                      trx_mutex_exit(c_lock->trx);
++
++                      if (wsrep_debug) fprintf(
++                              stderr,
++                              "WSREP: c_lock canceled %llu\n",
++                              (ulonglong) c_lock->trx->id);
++
++                      /* have to bail out here to avoid lock_set_lock... */
++                      return(lock);
++              }
++              trx_mutex_exit(c_lock->trx);
++      } else {
++              HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
++                          lock_rec_fold(space, page_no), lock);
++      }
++#else
+       HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
+                   lock_rec_fold(space, page_no), lock);
+-
++#endif /* WITH_WSREP */
+       if (!caller_owns_trx_mutex) {
+               trx_mutex_enter(trx);
+       }
+@@ -1871,7 +2093,6 @@ lock_rec_create(
+       MONITOR_INC(MONITOR_RECLOCK_CREATED);
+       MONITOR_INC(MONITOR_NUM_RECLOCK);
+-
+       return(lock);
+ }
+@@ -1886,6 +2107,9 @@ static
+ dberr_t
+ lock_rec_enqueue_waiting(
+ /*=====================*/
++#ifdef WITH_WSREP
++      lock_t*                 c_lock, /* conflicting lock */
++#endif
+       ulint                   type_mode,/*!< in: lock mode this
+                                       transaction is requesting:
+                                       LOCK_S or LOCK_X, possibly
+@@ -1942,8 +2166,17 @@ lock_rec_enqueue_waiting(
+       /* Enqueue the lock request that will wait to be granted, note that
+       we already own the trx mutex. */
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd) && 
++          trx->lock.was_chosen_as_deadlock_victim) {
++              return(DB_DEADLOCK);
++      }
++      lock = lock_rec_create(c_lock, thr,
++              type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
++#else
+       lock = lock_rec_create(
+               type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
++#endif /* WITH_WSREP */
+       /* Release the mutex to obey the latching order.
+       This is safe, because lock_deadlock_check_and_resolve()
+@@ -2044,7 +2277,19 @@ lock_rec_add_to_queue(
+               const lock_t*   other_lock
+                       = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT,
+                                                     block, heap_no, trx);
++#ifdef WITH_WSREP
++              /* this can potentionally assert with wsrep */
++              if (wsrep_on(trx->mysql_thd)) {
++                      if (wsrep_debug && other_lock) {
++                              fprintf(stderr, 
++                                      "WSREP: InnoDB assert ignored\n");
++                      }
++              } else {
++                      ut_a(!other_lock);
++              }
++#else
+               ut_a(!other_lock);
++#endif /* WITH_WSREP */
+       }
+ #endif /* UNIV_DEBUG */
+@@ -2072,7 +2317,16 @@ lock_rec_add_to_queue(
+               if (lock_get_wait(lock)
+                   && lock_rec_get_nth_bit(lock, heap_no)) {
+-
++#ifdef WITH_WSREP
++                      if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
++                              if (wsrep_debug) {
++                                      fprintf(stderr, 
++                                              "BF skipping wait: %lu\n", 
++                                              trx->id);
++                                      lock_rec_print(stderr, lock);
++                              }
++                } else
++#endif
+                       goto somebody_waits;
+               }
+       }
+@@ -2095,9 +2349,15 @@ lock_rec_add_to_queue(
+       }
+ somebody_waits:
++#ifdef WITH_WSREP
++      return(lock_rec_create(NULL, NULL,
++                      type_mode, block, heap_no, index, trx,
++                      caller_owns_trx_mutex));
++#else
+       return(lock_rec_create(
+                       type_mode, block, heap_no, index, trx,
+                       caller_owns_trx_mutex));
++#endif
+ }
+ /** Record locking request status */
+@@ -2160,9 +2420,13 @@ lock_rec_lock_fast(
+       if (lock == NULL) {
+               if (!impl) {
+                       /* Note that we don't own the trx mutex. */
++#ifdef WITH_WSREP
++                      lock = lock_rec_create(NULL, thr,
++                              mode, block, heap_no, index, trx, FALSE);
++#else
+                       lock = lock_rec_create(
+                               mode, block, heap_no, index, trx, FALSE);
+-
++#endif
+               }
+               status = LOCK_REC_SUCCESS_CREATED;
+       } else {
+@@ -2215,6 +2479,9 @@ lock_rec_lock_slow(
+       que_thr_t*              thr)    /*!< in: query thread */
+ {
+       trx_t*                  trx;
++#ifdef WITH_WSREP
++      lock_t*                 c_lock(NULL);
++#endif
+       dberr_t                 err = DB_SUCCESS;
+       ut_ad(lock_mutex_own());
+@@ -2239,18 +2506,30 @@ lock_rec_lock_slow(
+               /* The trx already has a strong enough lock on rec: do
+               nothing */
++#ifdef WITH_WSREP
++      } else if ((c_lock = (lock_t *)lock_rec_other_has_conflicting(
++                      static_cast<enum lock_mode>(mode),
++                      block, heap_no, trx))) {
++#else
+       } else if (lock_rec_other_has_conflicting(
+                       static_cast<enum lock_mode>(mode),
+                       block, heap_no, trx)) {
+-
++#endif /* WITH_WSREP */
+               /* If another transaction has a non-gap conflicting
+               request in the queue, as this transaction does not
+               have a lock strong enough already granted on the
+               record, we have to wait. */
++#ifdef WITH_WSREP
++              /* c_lock is NULL here if jump to enqueue_waiting happened
++              but it's ok because lock is not NULL in that case and c_lock
++              is not used. */
++              err = lock_rec_enqueue_waiting(c_lock,
++                      mode, block, heap_no, index, thr);
++#else
+               err = lock_rec_enqueue_waiting(
+                       mode, block, heap_no, index, thr);
+-
++#endif /* WITH_WSREP */
+       } else if (!impl) {
+               /* Set the requested lock on the record, note that
+               we already own the transaction mutex. */
+@@ -2355,7 +2634,13 @@ lock_rec_has_to_wait_in_queue(
+               if (heap_no < lock_rec_get_n_bits(lock)
+                   && (p[bit_offset] & bit_mask)
+                   && lock_has_to_wait(wait_lock, lock)) {
+-
++#ifdef WITH_WSREP
++                      if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) &&
++                          wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) {
++                              /* don't wait for another BF lock */
++                              continue;
++                      }
++#endif
+                       return(lock);
+               }
+       }
+@@ -3739,9 +4024,19 @@ lock_deadlock_select_victim(
+               /* The joining  transaction is 'smaller',
+               choose it as the victim and roll it back. */
++#ifdef WITH_WSREP
++        if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE))
++              return(ctx->wait_lock->trx);
++      else
++#endif /* WITH_WSREP */
+               return(ctx->start);
+       }
++#ifdef WITH_WSREP
++      if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE))
++              return(ctx->start);
++      else
++#endif /* WITH_WSREP */
+       return(ctx->wait_lock->trx);
+ }
+@@ -3872,6 +4167,11 @@ lock_deadlock_search(
+                       ctx->too_deep = TRUE;
+                       /* Select the joining transaction as the victim. */
++#ifdef WITH_WSREP
++                      if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE))
++                              return(ctx->wait_lock->trx->id);
++                      else
++#endif /* WITH_WSREP */
+                       return(ctx->start->id);
+               } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
+@@ -3889,6 +4189,11 @@ lock_deadlock_search(
+                               ctx->too_deep = TRUE;
++#ifdef WITH_WSREP
++                              if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE))
++                              return(lock->trx->id);
++                      else
++#endif /* WITH_WSREP */
+                               return(ctx->start->id);
+                       }
+@@ -4005,11 +4310,21 @@ lock_deadlock_check_and_resolve(
+               if (ctx.too_deep) {
+                       ut_a(trx == ctx.start);
++
++#ifdef WITH_WSREP
++                      if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE))
++                      {
++#endif /* WITH_WSREP */
+                       ut_a(victim_trx_id == trx->id);
+                       if (!srv_read_only_mode) {
+                               lock_deadlock_joining_trx_print(trx, lock);
+                       }
++#ifdef WITH_WSREP
++                      } else {
++                        /* BF processor */;
++                      }
++#endif /* WITH_WSREP */
+                       MONITOR_INC(MONITOR_DEADLOCK);
+@@ -4047,6 +4362,9 @@ UNIV_INLINE
+ lock_t*
+ lock_table_create(
+ /*==============*/
++#ifdef WITH_WSREP
++      lock_t*         c_lock, /* conflicting lock */
++#endif
+       dict_table_t*   table,  /*!< in/out: database table
+                               in dictionary cache */
+       ulint           type_mode,/*!< in: lock mode possibly ORed with
+@@ -4090,7 +4408,46 @@ lock_table_create(
+       ut_ad(table->n_ref_count > 0 || !table->can_be_evicted);
+       UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock);
++#ifdef WITH_WSREP
++      if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
++              UT_LIST_INSERT_AFTER(
++                  un_member.tab_lock.locks, table->locks, c_lock, lock);
++        } else {
++              UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
++        }
++
++      if (c_lock) trx_mutex_enter(c_lock->trx);
++      if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
++
++              c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE;
++
++              if (wsrep_debug) wsrep_print_wait_locks(c_lock);
++
++              /* have to release trx mutex for the duration of
++                 victim lock release. This will eventually call
++                 lock_grant, which wants to grant trx mutex again
++              */
++              /* caller has trx_mutex, have to release for lock cancel */
++              trx_mutex_exit(trx);
++              lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock);
++              trx_mutex_enter(trx);
++
++              /* trx might not wait for c_lock, but some other lock
++              does not matter if wait_lock was released above
++              */
++              if (c_lock->trx->lock.wait_lock == c_lock) {
++                      lock_reset_lock_and_trx_wait(lock);
++              }
++
++              if (wsrep_debug) {
++                      fprintf(stderr, "WSREP: c_lock canceled %llu\n",
++                              (ulonglong) c_lock->trx->id);
++              }
++      }
++      if (c_lock) trx_mutex_exit(c_lock->trx);
++#else
+       UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
++#endif /* WITH_WSREP */
+       if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
+@@ -4247,12 +4604,15 @@ static
+ dberr_t
+ lock_table_enqueue_waiting(
+ /*=======================*/
++#ifdef WITH_WSREP
++      lock_t*         c_lock, /* conflicting lock */
++#endif
+       ulint           mode,   /*!< in: lock mode this transaction is
+                               requesting */
+       dict_table_t*   table,  /*!< in/out: table */
+       que_thr_t*      thr)    /*!< in: query thread */
+ {
+-      trx_t*          trx;
++      trx_t*          trx;
+       lock_t*         lock;
+       trx_id_t        victim_trx_id;
+@@ -4291,7 +4651,14 @@ lock_table_enqueue_waiting(
+       /* Enqueue the lock request that will wait to be granted */
++#ifdef WITH_WSREP
++      if (trx->lock.was_chosen_as_deadlock_victim) {
++              return(DB_DEADLOCK);
++      }
++      lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx);
++#else
+       lock = lock_table_create(table, mode | LOCK_WAIT, trx);
++#endif
+       /* Release the mutex to obey the latching order.
+       This is safe, because lock_deadlock_check_and_resolve()
+@@ -4363,6 +4730,13 @@ lock_table_other_has_incompatible(
+                   && !lock_mode_compatible(lock_get_mode(lock), mode)
+                   && (wait || !lock_get_wait(lock))) {
++#ifdef WITH_WSREP
++                      if (wsrep_debug) 
++                              fprintf(stderr, "WSREP: table lock abort");
++                      trx_mutex_enter(lock->trx);
++                      wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
++                      trx_mutex_exit(lock->trx);
++#endif
+                       return(lock);
+               }
+       }
+@@ -4424,9 +4798,18 @@ lock_table(
+       mode: this trx may have to wait */
+       if (wait_for != NULL) {
++#ifdef WITH_WSREP
++        err = lock_table_enqueue_waiting((lock_t *)wait_for, 
++                      mode | flags, table, thr);
++#else
+               err = lock_table_enqueue_waiting(mode | flags, table, thr);
++#endif /* WITH_WSREP */
+       } else {
++#ifdef WITH_WSREP
++        lock_table_create((lock_t *)wait_for, table, mode | flags, trx);
++#else
+               lock_table_create(table, mode | flags, trx);
++#endif /* WITH_WSREP */
+               ut_a(!flags || mode == LOCK_S || mode == LOCK_X);
+@@ -4464,7 +4847,11 @@ lock_table_ix_resurrect(
+                     trx, LOCK_WAIT, table, LOCK_IX));
+       trx_mutex_enter(trx);
++#ifdef WITH_WSREP
++      lock_table_create(NULL, table, LOCK_IX, trx);
++#else
+       lock_table_create(table, LOCK_IX, trx);
++#endif /* WITH_WSREP */
+       lock_mutex_exit();
+       trx_mutex_exit(trx);
+ }
+@@ -5612,6 +5999,7 @@ lock_rec_queue_validate(
+               if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) {
++#ifndef WITH_WSREP
+                       enum lock_mode  mode;
+                       if (lock_get_mode(lock) == LOCK_S) {
+@@ -5621,6 +6009,7 @@ lock_rec_queue_validate(
+                       }
+                       ut_a(!lock_rec_other_has_expl_req(
+                                    mode, 0, 0, block, heap_no, lock->trx));
++#endif /* WITH_WSREP */
+               } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
+@@ -5924,6 +6313,9 @@ lock_rec_insert_check_and_lock(
+       lock_t*         lock;
+       dberr_t         err;
+       ulint           next_rec_heap_no;
++#ifdef WITH_WSREP
++      lock_t *c_lock;
++#endif
+       ibool           inherit_in = *inherit;
+       ut_ad(block->frame == page_align(rec));
+@@ -5981,17 +6373,29 @@ lock_rec_insert_check_and_lock(
+       had to wait for their insert. Both had waiting gap type lock requests
+       on the successor, which produced an unnecessary deadlock. */
++#ifdef WITH_WSREP
++      if ((c_lock = (lock_t *)lock_rec_other_has_conflicting(
++                  static_cast<enum lock_mode>(
++                          LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION),
++                  block, next_rec_heap_no, trx))) {
++#else
+       if (lock_rec_other_has_conflicting(
+                   static_cast<enum lock_mode>(
+                           LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION),
+                   block, next_rec_heap_no, trx)) {
+-
++#endif /* WITH_WSREP */
+               /* Note that we may get DB_SUCCESS also here! */
+               trx_mutex_enter(trx);
++#ifdef WITH_WSREP
++              err = lock_rec_enqueue_waiting(c_lock,
++                      LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
++                      block, next_rec_heap_no, index, thr);
++#else
+               err = lock_rec_enqueue_waiting(
+                       LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
+                       block, next_rec_heap_no, index, thr);
++#endif /* WITH_WSREP */
+               trx_mutex_exit(trx);
+       } else {
+@@ -6070,8 +6474,10 @@ lock_rec_convert_impl_to_expl(
+               trx_is_active(trx_id, NULL) check below, because we are not
+               holding lock_mutex. */
++#ifndef WITH_WSREP
+               ut_ad(!lock_rec_other_trx_holds_expl(LOCK_S | LOCK_REC_NOT_GAP,
+                                                    trx_id, rec, block));
++#endif /* WITH_WSREP */
+       }
+       if (trx_id != 0) {
+diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc
+index a1c35e2..9d1a4da 100644
+--- a/storage/innobase/lock/lock0wait.cc
++++ b/storage/innobase/lock/lock0wait.cc
+@@ -184,6 +184,28 @@ lock_wait_table_reserve_slot(
+       return(NULL);
+ }
++#ifdef WITH_WSREP
++/*********************************************************************//**
++check if lock timeout was for priority thread, 
++as a side effect trigger lock monitor
++@return       false for regular lock timeout */
++static ibool
++wsrep_is_BF_lock_timeout(
++/*====================*/
++    trx_t* trx) /* in: trx to check for lock priority */
++{
++      if (wsrep_on(trx->mysql_thd) &&
++          wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
++              fprintf(stderr, "WSREP: BF lock wait long\n");
++                srv_print_innodb_monitor      = TRUE;
++                srv_print_innodb_lock_monitor         = TRUE;
++                os_event_set(srv_monitor_event);
++                return TRUE;
++      }
++      return FALSE;
++ }
++#endif /* WITH_WSREP */
++
+ /***************************************************************//**
+ Puts a user OS thread to wait for a lock to be released. If an error
+ occurs during the wait trx->error_state associated with thr is
+@@ -375,9 +397,15 @@ lock_wait_suspend_thread(
+       if (lock_wait_timeout < 100000000
+           && wait_time > (double) lock_wait_timeout) {
++#ifdef WITH_WSREP
++                if (!wsrep_is_BF_lock_timeout(trx)) {
++#endif /* WITH_WSREP */
+               trx->error_state = DB_LOCK_WAIT_TIMEOUT;
++#ifdef WITH_WSREP
++                }
++#endif /* WITH_WSREP */
+               MONITOR_INC(MONITOR_TIMEOUT);
+       }
+@@ -461,8 +489,14 @@ lock_wait_check_and_cancel(
+               if (trx->lock.wait_lock) {
+                       ut_a(trx->lock.que_state == TRX_QUE_LOCK_WAIT);
++#ifdef WITH_WSREP
++                        if (!wsrep_is_BF_lock_timeout(trx)) {
++#endif /* WITH_WSREP */
+                       lock_cancel_waiting_and_release(trx->lock.wait_lock);
++#ifdef WITH_WSREP
++                        }
++#endif /* WITH_WSREP */
+               }
+               lock_mutex_exit();
+diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
+index fb7e8ca..41372a8 100644
+--- a/storage/innobase/os/os0file.cc
++++ b/storage/innobase/os/os0file.cc
+@@ -87,6 +87,12 @@ UNIV_INTERN os_ib_mutex_t   os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
+ /* In simulated aio, merge at most this many consecutive i/os */
+ #define OS_AIO_MERGE_N_CONSECUTIVE    64
++#ifdef WITH_INNODB_DISALLOW_WRITES
++#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event)
++#else
++#define WAIT_ALLOW_WRITES() do { } while (0)
++#endif /* WITH_INNODB_DISALLOW_WRITES */
++
+ /**********************************************************************
+ InnoDB AIO Implementation:
+@@ -763,7 +769,11 @@ os_file_create_tmpfile(void)
+ /*========================*/
+ {
+       FILE*   file    = NULL;
+-      int     fd      = innobase_mysql_tmpfile();
++      int     fd;
++      WAIT_ALLOW_WRITES();
++      fd      = innobase_mysql_tmpfile();
++
++      ut_ad(!srv_read_only_mode);
+       ut_ad(!srv_read_only_mode);
+@@ -1089,6 +1099,7 @@ os_file_create_directory(
+       return(TRUE);
+ #else
+       int     rcode;
++      WAIT_ALLOW_WRITES();
+       rcode = mkdir(pathname, 0770);
+@@ -1215,6 +1226,8 @@ os_file_create_simple_func(
+ #else /* __WIN__ */
+       int             create_flag;
++      if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
++              WAIT_ALLOW_WRITES();
+       ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT));
+       ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT));
+@@ -1382,6 +1395,8 @@ os_file_create_simple_no_error_handling_func(
+       int             create_flag;
+       ut_a(name);
++      if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
++              WAIT_ALLOW_WRITES();
+       ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT));
+       ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT));
+@@ -1673,6 +1688,8 @@ os_file_create_func(
+ #else /* __WIN__ */
+       int             create_flag;
+       const char*     mode_str        = NULL;
++      if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
++              WAIT_ALLOW_WRITES();
+       on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT
+               ? TRUE : FALSE;
+@@ -1852,6 +1869,7 @@ loop:
+       goto loop;
+ #else
+       int     ret;
++      WAIT_ALLOW_WRITES();
+       ret = unlink(name);
+@@ -1916,6 +1934,7 @@ loop:
+       goto loop;
+ #else
+       int     ret;
++      WAIT_ALLOW_WRITES();
+       ret = unlink(name);
+@@ -1969,6 +1988,7 @@ os_file_rename_func(
+       return(FALSE);
+ #else
+       int     ret;
++      WAIT_ALLOW_WRITES();
+       ret = rename(oldpath, newpath);
+@@ -2180,6 +2200,7 @@ os_file_set_eof(
+       HANDLE h = (HANDLE) _get_osfhandle(fileno(file));
+       return(SetEndOfFile(h));
+ #else /* __WIN__ */
++      WAIT_ALLOW_WRITES();
+       return(!ftruncate(fileno(file), ftell(file)));
+ #endif /* __WIN__ */
+ }
+@@ -2274,6 +2295,7 @@ os_file_flush_func(
+       return(FALSE);
+ #else
+       int     ret;
++      WAIT_ALLOW_WRITES();
+ #if defined(HAVE_DARWIN_THREADS)
+ # ifndef F_FULLFSYNC
+@@ -2969,6 +2991,7 @@ retry:
+       return(FALSE);
+ #else
+       ssize_t ret;
++      WAIT_ALLOW_WRITES();
+       ret = os_file_pwrite(file, buf, n, offset);
+diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
+index 0d7b7c1..9540211 100644
+--- a/storage/innobase/rem/rem0rec.cc
++++ b/storage/innobase/rem/rem0rec.cc
+@@ -33,6 +33,9 @@ Created 5/30/1994 Heikki Tuuri
+ #include "mtr0mtr.h"
+ #include "mtr0log.h"
+ #include "fts0fts.h"
++#ifdef WITH_WSREP
++#include <ha_prototypes.h>
++#endif /* WITH_WSREP */
+ /*                    PHYSICAL RECORD (OLD STYLE)
+                       ===========================
+@@ -1961,3 +1964,133 @@ rec_get_trx_id(
+ }
+ # endif /* UNIV_DEBUG */
+ #endif /* !UNIV_HOTBACKUP */
++#ifdef WITH_WSREP
++dberr_t
++wsrep_rec_get_foreign_key(
++      byte            *buf,     /* out: extracted key */
++      ulint           *buf_len, /* in/out: length of buf */
++      const rec_t*    rec,      /* in: physical record */
++      dict_index_t*   index_for,  /* in: index in foreign table */
++      dict_index_t*   index_ref,  /* in: index in referenced table */
++      ibool           new_protocol) /* in: protocol > 1 */
++{
++      const byte*     data;
++      ulint           len;
++      ulint           key_len = 0;
++      ulint           i;
++      uint            key_parts;
++      mem_heap_t*     heap    = NULL;
++      ulint           offsets_[REC_OFFS_NORMAL_SIZE];
++        const ulint*    offsets;
++
++      ut_ad(index_for);
++      ut_ad(index_ref);
++
++        rec_offs_init(offsets_);
++      offsets = rec_get_offsets(rec, index_for, offsets_, 
++                                ULINT_UNDEFINED, &heap);
++
++      ut_ad(rec_offs_validate(rec, NULL, offsets));
++
++      ut_ad(rec);
++
++      key_parts = dict_index_get_n_unique_in_tree(index_for);
++      for (i = 0; 
++           i < key_parts && 
++             (index_for->type & DICT_CLUSTERED || i < key_parts - 1); 
++           i++) {
++              dict_field_t*     field_f = 
++                      dict_index_get_nth_field(index_for, i);
++              const dict_col_t* col_f = dict_field_get_col(field_f);
++                dict_field_t*   field_r = 
++                      dict_index_get_nth_field(index_ref, i);
++              const dict_col_t* col_r = dict_field_get_col(field_r);
++
++              data = rec_get_nth_field(rec, offsets, i, &len);
++              if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) > 
++                  *buf_len) {
++                      fprintf (stderr, 
++                               "WSREP: FK key len exceeded %lu %lu %lu\n", 
++                               key_len, len, *buf_len);
++                      goto err_out;
++              }
++
++              if (len == UNIV_SQL_NULL) {
++                      ut_a(!(col_f->prtype & DATA_NOT_NULL));
++                      *buf++ = 1;
++                      key_len++;
++              } else if (!new_protocol) {
++                      if (!(col_r->prtype & DATA_NOT_NULL)) {
++                              *buf++ = 0;
++                              key_len++;
++                      }
++                      memcpy(buf, data, len);
++                      *buf_len = wsrep_innobase_mysql_sort(
++                              (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK),
++                              (uint)dtype_get_charset_coll(col_f->prtype),
++                              buf, len, *buf_len);
++              } else { /* new protocol */
++                      if (!(col_r->prtype & DATA_NOT_NULL)) {
++                              *buf++ = 0;
++                              key_len++;
++                      }
++                      switch (col_f->mtype) {
++                      case DATA_INT: {
++                              byte* ptr = buf+len;
++                              for (;;) {
++                                      ptr--;
++                                      *ptr = *data;
++                                      if (ptr == buf) {
++                                              break;
++                                      }
++                                      data++;
++                              }
++              
++                              if (!(col_f->prtype & DATA_UNSIGNED)) {
++                                      buf[len-1] = (byte) (buf[len-1] ^ 128);
++                              }
++
++                              break;
++                      }
++                      case DATA_VARCHAR:
++                      case DATA_VARMYSQL:
++                      case DATA_CHAR:
++                      case DATA_MYSQL:
++                              /* Copy the actual data */
++                              ut_memcpy(buf, data, len);
++                              len = wsrep_innobase_mysql_sort(
++                                      (int)
++                                      (col_f->prtype & DATA_MYSQL_TYPE_MASK),
++                                      (uint)
++                                      dtype_get_charset_coll(col_f->prtype),
++                                      buf, len, *buf_len);
++                              break;
++                      case DATA_BLOB:
++                      case DATA_BINARY:
++                              memcpy(buf, data, len);
++                              break;
++                      default: 
++                              break;
++                      }
++
++                      key_len += len;
++                      buf     += len;
++              }
++      }
++
++      rec_validate(rec, offsets);
++
++      if (UNIV_LIKELY_NULL(heap)) {
++              mem_heap_free(heap);
++      }
++
++      *buf_len = key_len;
++      return DB_SUCCESS;
++
++ err_out:
++      if (UNIV_LIKELY_NULL(heap)) {
++              mem_heap_free(heap);
++      }
++      return DB_ERROR;
++}
++#endif // WITH_WSREP
+diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
+index e31b447..3c3ccf4 100644
+--- a/storage/innobase/row/row0ins.cc
++++ b/storage/innobase/row/row0ins.cc
+@@ -920,6 +920,14 @@ row_ins_invalidate_query_cache(
+       innobase_invalidate_query_cache(thr_get_trx(thr), buf, len);
+       mem_free(buf);
+ }
++#ifdef WITH_WSREP
++dberr_t wsrep_append_foreign_key(trx_t *trx,  
++                               dict_foreign_t*        foreign,
++                               const rec_t*           clust_rec,
++                               dict_index_t*          clust_index,
++                               ibool                  referenced,
++                               ibool                  shared);
++#endif /* WITH_WSREP */
+ /*********************************************************************//**
+ Perform referential actions or checks when a parent row is deleted or updated
+@@ -1271,6 +1279,18 @@ row_ins_foreign_check_on_constraint(
+       cascade->state = UPD_NODE_UPDATE_CLUSTERED;
++#ifdef WITH_WSREP
++      err = wsrep_append_foreign_key(
++                                     thr_get_trx(thr),
++                                     foreign,
++                                     clust_rec, 
++                                     clust_index,
++                                     FALSE, FALSE);
++      if (err != DB_SUCCESS) {
++              fprintf(stderr, 
++                      "WSREP: foreign key append failed: %d\n", err);
++      } else
++#endif
+       err = row_update_cascade_for_mysql(thr, cascade,
+                                          foreign->foreign_table);
+@@ -1603,7 +1623,14 @@ run_again:
+                               if (check_ref) {
+                                       err = DB_SUCCESS;
+-
++#ifdef WITH_WSREP
++                                      err = wsrep_append_foreign_key(
++                                              thr_get_trx(thr),
++                                              foreign,
++                                              rec, 
++                                              check_index, 
++                                              check_ref, TRUE);
++#endif /* WITH_WSREP */
+                                       goto end_scan;
+                               } else if (foreign->type != 0) {
+                                       /* There is an ON UPDATE or ON DELETE
+diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
+index fcd5433..5a8987a 100644
+--- a/storage/innobase/row/row0upd.cc
++++ b/storage/innobase/row/row0upd.cc
+@@ -51,6 +51,9 @@ Created 12/27/1996 Heikki Tuuri
+ #include "pars0sym.h"
+ #include "eval0eval.h"
+ #include "buf0lru.h"
++#ifdef WITH_WSREP
++extern my_bool wsrep_debug;
++#endif
+ #include <algorithm>
+ /* What kind of latch and lock can we assume when the control comes to
+@@ -162,6 +165,42 @@ row_upd_index_is_referenced(
+       return(is_referenced);
+ }
++#ifdef WITH_WSREP
++static
++ibool
++wsrep_row_upd_index_is_foreign(
++/*========================*/
++      dict_index_t*   index,  /*!< in: index */
++      trx_t*          trx)    /*!< in: transaction */
++{
++      dict_table_t*   table           = index->table;
++      ibool           froze_data_dict = FALSE;
++      ibool           is_referenced   = FALSE;
++
++      if (table->foreign_set.empty()) {
++              return(FALSE);
++      }
++
++      if (trx->dict_operation_lock_mode == 0) {
++              row_mysql_freeze_data_dictionary(trx);
++              froze_data_dict = TRUE;
++      }
++
++      dict_foreign_set::iterator      it
++              = std::find_if(table->foreign_set.begin(),
++                             table->foreign_set.end(),
++                             dict_foreign_with_foreign_index(index));
++
++      is_referenced = (it != table->foreign_set.end());
++
++      if (froze_data_dict) {
++              row_mysql_unfreeze_data_dictionary(trx);
++      }
++
++      return(is_referenced);
++}
++#endif /* WITH_WSREP */
++
+ /*********************************************************************//**
+ Checks if possible foreign key constraints hold after a delete of the record
+ under pcur.
+@@ -281,7 +320,6 @@ run_again:
+       }
+       err = DB_SUCCESS;
+-
+ func_exit:
+       if (got_s_lock) {
+               row_mysql_unfreeze_data_dictionary(trx);
+@@ -293,6 +331,127 @@ func_exit:
+       return(err);
+ }
++#ifdef WITH_WSREP
++static
++dberr_t
++wsrep_row_upd_check_foreign_constraints(
++/*=================================*/
++      upd_node_t*     node,   /*!< in: row update node */
++      btr_pcur_t*     pcur,   /*!< in: cursor positioned on a record; NOTE: the
++                              cursor position is lost in this function! */
++      dict_table_t*   table,  /*!< in: table in question */
++      dict_index_t*   index,  /*!< in: index of the cursor */
++      ulint*          offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */
++      que_thr_t*      thr,    /*!< in: query thread */
++      mtr_t*          mtr)    /*!< in: mtr */
++{
++      dict_foreign_t* foreign;
++      mem_heap_t*     heap;
++      dtuple_t*       entry;
++      trx_t*          trx;
++      const rec_t*    rec;
++      ulint           n_ext;
++      dberr_t         err;
++      ibool           got_s_lock      = FALSE;
++      ibool           opened          = FALSE;
++
++      if (table->foreign_set.empty()) {
++              return(DB_SUCCESS);
++      }
++
++      trx = thr_get_trx(thr);
++
++      /* TODO: make native slave thread bail out here */
++
++      rec = btr_pcur_get_rec(pcur);
++      ut_ad(rec_offs_validate(rec, index, offsets));
++
++      heap = mem_heap_create(500);
++
++      entry = row_rec_to_index_entry(rec, index, offsets,
++                                     &n_ext, heap);
++
++      mtr_commit(mtr);
++
++      mtr_start(mtr);
++
++      if (trx->dict_operation_lock_mode == 0) {
++              got_s_lock = TRUE;
++
++              row_mysql_freeze_data_dictionary(trx);
++      }
++
++run_again:
++
++      for (dict_foreign_set::iterator it = table->foreign_set.begin();
++           it != table->foreign_set.end();
++           ++it) {
++
++              foreign = *it;
++              /* Note that we may have an update which updates the index
++              record, but does NOT update the first fields which are
++              referenced in a foreign key constraint. Then the update does
++              NOT break the constraint. */
++
++              if (foreign->foreign_index == index
++                  && (node->is_delete
++                      || row_upd_changes_first_fields_binary(
++                              entry, index, node->update,
++                              foreign->n_fields))) {
++
++                      if (foreign->referenced_table == NULL) {
++                              foreign->referenced_table = 
++                                      dict_table_open_on_name(
++                                        foreign->referenced_table_name_lookup,
++                                        FALSE, FALSE, DICT_ERR_IGNORE_NONE);
++                              opened = TRUE;
++                      }
++
++                      if (foreign->referenced_table) {
++                              os_inc_counter(dict_sys->mutex,
++                                             foreign->referenced_table
++                                             ->n_foreign_key_checks_running);
++                      }
++
++                      /* NOTE that if the thread ends up waiting for a lock
++                      we will release dict_operation_lock temporarily!
++                      But the counter on the table protects 'foreign' from
++                      being dropped while the check is running. */
++
++                      err = row_ins_check_foreign_constraint(
++                              TRUE, foreign, table, entry, thr);
++
++                      if (foreign->referenced_table) {
++                              os_dec_counter(dict_sys->mutex,
++                                             foreign->referenced_table
++                                             ->n_foreign_key_checks_running);
++
++                              if (opened == TRUE) {
++                                      dict_table_close(foreign->referenced_table, TRUE, FALSE);
++                                      opened = FALSE;
++                              }
++                      }
++
++                      /* Some table foreign key dropped, try again */
++                      if (err == DB_DICT_CHANGED) {
++                              goto run_again;
++                      } else if (err != DB_SUCCESS) {
++                              goto func_exit;
++                      }
++              }
++      }
++
++      err = DB_SUCCESS;
++func_exit:
++      if (got_s_lock) {
++              row_mysql_unfreeze_data_dictionary(trx);
++      }
++
++      mem_heap_free(heap);
++
++      return(err);
++}
++#endif /* WITH_WSREP */
+ /*********************************************************************//**
+ Creates an update node for a query graph.
+@@ -1667,6 +1826,9 @@ row_upd_sec_index_entry(
+       index = node->index;
+       referenced = row_upd_index_is_referenced(index, trx);
++#ifdef WITH_WSREP
++      ibool foreign = wsrep_row_upd_index_is_foreign(index, trx);
++#endif /* WITH_WSREP */
+       heap = mem_heap_create(1024);
+@@ -1794,6 +1956,9 @@ row_upd_sec_index_entry(
+               row_ins_sec_index_entry() below */
+               if (!rec_get_deleted_flag(
+                           rec, dict_table_is_comp(index->table))) {
++#ifdef WITH_WSREP
++                      que_node_t *parent = que_node_get_parent(node);
++#endif /* WITH_WSREP */
+                       err = btr_cur_del_mark_set_sec_rec(
+                               0, btr_cur, TRUE, thr, &mtr);
+@@ -1811,6 +1976,37 @@ row_upd_sec_index_entry(
+                                       node, &pcur, index->table,
+                                       index, offsets, thr, &mtr);
+                       }
++#ifdef WITH_WSREP
++                      if (err == DB_SUCCESS && !referenced                  &&
++                          !(parent && que_node_get_type(parent) ==
++                              QUE_NODE_UPDATE                               &&
++                            ((upd_node_t*)parent)->cascade_node == node)    &&
++                          foreign
++                      ) {
++                              ulint*  offsets =
++                                      rec_get_offsets(
++                                              rec, index, NULL, ULINT_UNDEFINED,
++                                              &heap);
++                              err = wsrep_row_upd_check_foreign_constraints(
++                                      node, &pcur, index->table,
++                                      index, offsets, thr, &mtr);
++                              switch (err) {
++                              case DB_SUCCESS:
++                              case DB_NO_REFERENCED_ROW:
++                                      err = DB_SUCCESS;
++                                      break;
++                              case DB_DEADLOCK:
++                                      if (wsrep_debug) fprintf (stderr, 
++                                              "WSREP: sec index FK check fail for deadlock");
++                                      break;
++                              default:
++                                      fprintf (stderr, 
++                                               "WSREP: referenced FK check fail: %d", 
++                                               (int)err);
++                                      break;
++                              }
++                      }
++#endif /* WITH_WSREP */
+               }
+               break;
+       }
+@@ -1965,6 +2161,9 @@ row_upd_clust_rec_by_insert(
+       que_thr_t*      thr,    /*!< in: query thread */
+       ibool           referenced,/*!< in: TRUE if index may be referenced in
+                               a foreign key constraint */
++#ifdef WITH_WSREP
++      ibool           foreign, /*!< in: TRUE if index is foreign key index */
++#endif /* WITH_WSREP */
+       mtr_t*          mtr)    /*!< in/out: mtr; gets committed here */
+ {
+       mem_heap_t*     heap;
+@@ -1978,6 +2177,9 @@ row_upd_clust_rec_by_insert(
+       rec_t*          rec;
+       ulint*          offsets                 = NULL;
++#ifdef WITH_WSREP
++      que_node_t *parent = que_node_get_parent(node);
++#endif /* WITH_WSREP */
+       ut_ad(node);
+       ut_ad(dict_index_is_clust(index));
+@@ -2060,6 +2262,34 @@ err_exit:
+                               goto err_exit;
+                       }
+               }
++#ifdef WITH_WSREP
++              if (!referenced                                              &&
++                  !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
++                    ((upd_node_t*)parent)->cascade_node == node)           &&
++                  foreign
++              ) {
++                      err = wsrep_row_upd_check_foreign_constraints(
++                              node, pcur, table, index, offsets, thr, mtr);
++                      switch (err) {
++                      case DB_SUCCESS:
++                      case DB_NO_REFERENCED_ROW:
++                              err = DB_SUCCESS;
++                              break;
++                      case DB_DEADLOCK:
++                              if (wsrep_debug) fprintf (stderr, 
++                                      "WSREP: insert FK check fail for deadlock");
++                              break;
++                      default:
++                              fprintf (stderr, 
++                                      "WSREP: referenced FK check fail: %d", 
++                                       (int)err);
++                              break;
++                      }
++                      if (err != DB_SUCCESS) {
++                              goto err_exit;
++                      }
++              }
++#endif /* WITH_WSREP */
+       }
+       mtr_commit(mtr);
+@@ -2252,11 +2482,18 @@ row_upd_del_mark_clust_rec(
+       ibool           referenced,
+                               /*!< in: TRUE if index may be referenced in
+                               a foreign key constraint */
++#ifdef WITH_WSREP
++      ibool           foreign,/*!< in: TRUE if index is foreign key index */
++#endif /* WITH_WSREP */
+       mtr_t*          mtr)    /*!< in: mtr; gets committed here */
+ {
+       btr_pcur_t*     pcur;
+       btr_cur_t*      btr_cur;
+       dberr_t         err;
++#ifdef WITH_WSREP
++      rec_t*          rec;
++      que_node_t *parent = que_node_get_parent(node);
++#endif /* WITH_WSREP */
+       ut_ad(node);
+       ut_ad(dict_index_is_clust(index));
+@@ -2273,8 +2510,16 @@ row_upd_del_mark_clust_rec(
+       /* Mark the clustered index record deleted; we do not have to check
+       locks, because we assume that we have an x-lock on the record */
++#ifdef WITH_WSREP
++      rec = btr_cur_get_rec(btr_cur);
++#endif /* WITH_WSREP */
++
+       err = btr_cur_del_mark_set_clust_rec(
++#ifdef WITH_WSREP
++              btr_cur_get_block(btr_cur), rec,
++#else
+               btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur),
++#endif /* WITH_WSREP */
+               index, offsets, thr, mtr);
+       if (err == DB_SUCCESS && referenced) {
+               /* NOTE that the following call loses the position of pcur ! */
+@@ -2282,6 +2527,32 @@ row_upd_del_mark_clust_rec(
+               err = row_upd_check_references_constraints(
+                       node, pcur, index->table, index, offsets, thr, mtr);
+       }
++#ifdef WITH_WSREP
++      if (err == DB_SUCCESS && !referenced                         &&
++          !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
++            ((upd_node_t*)parent)->cascade_node == node)           &&
++          thr_get_trx(thr)                                         &&
++          foreign
++      ) {
++              err = wsrep_row_upd_check_foreign_constraints(
++                      node, pcur, index->table, index, offsets, thr, mtr);
++              switch (err) {
++              case DB_SUCCESS:
++              case DB_NO_REFERENCED_ROW:
++                      err = DB_SUCCESS;
++                      break;
++              case DB_DEADLOCK:
++                      if (wsrep_debug) fprintf (stderr, 
++                              "WSREP: clust rec FK check fail for deadlock");
++                      break;
++              default:
++                      fprintf (stderr, 
++                              "WSREP: clust rec referenced FK check fail: %d", 
++                               (int)err);
++                      break;
++              }
++      }
++#endif /* WITH_WSREP */
+       mtr_commit(mtr);
+@@ -2314,6 +2585,10 @@ row_upd_clust_step(
+       index = dict_table_get_first_index(node->table);
+       referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
++#ifdef WITH_WSREP
++      ibool foreign = wsrep_row_upd_index_is_foreign(
++              index, thr_get_trx(thr));
++#endif /* WITH_WSREP */
+       pcur = node->pcur;
+@@ -2408,7 +2683,11 @@ row_upd_clust_step(
+       if (node->is_delete) {
+               err = row_upd_del_mark_clust_rec(
++#ifdef WITH_WSREP
++                      node, index, offsets, thr, referenced, foreign, &mtr);
++#else
+                       node, index, offsets, thr, referenced, &mtr);
++#endif /* WITH_WSREP */
+               if (err == DB_SUCCESS) {
+                       node->state = UPD_NODE_UPDATE_ALL_SEC;
+@@ -2453,7 +2732,11 @@ row_upd_clust_step(
+               externally! */
+               err = row_upd_clust_rec_by_insert(
++#ifdef WITH_WSREP
++                      node, index, thr, referenced, foreign, &mtr);
++#else
+                       node, index, thr, referenced, &mtr);
++#endif /* WITH_WSREP */
+               if (err != DB_SUCCESS) {
+diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc
+index dc3c0b1..fb7fad3 100644
+--- a/storage/innobase/srv/srv0conc.cc
++++ b/storage/innobase/srv/srv0conc.cc
+@@ -42,6 +42,10 @@ Created 2011/04/18 Sunny Bains
+ #include "trx0trx.h"
+ #include "mysql/plugin.h"
++#ifdef WITH_WSREP
++extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
++extern my_bool wsrep_debug;
++#endif
+ /** Number of times a thread is allowed to enter InnoDB within the same
+ SQL query after it has once got the ticket. */
+@@ -86,6 +90,9 @@ struct srv_conc_slot_t{
+                                       reserved may still be TRUE at that
+                                       point */
+       srv_conc_node_t srv_conc_queue; /*!< queue node */
++#ifdef WITH_WSREP
++      void                            *thd;           /*!< to see priority */
++#endif
+ };
+ /** Queue of threads waiting to get in */
+@@ -145,6 +152,9 @@ srv_conc_init(void)
+               conc_slot->event = os_event_create();
+               ut_a(conc_slot->event);
++#ifdef WITH_WSREP
++              conc_slot->thd = NULL;
++#endif /* WITH_WSREP */
+       }
+ #endif /* !HAVE_ATOMIC_BUILTINS */
+ }
+@@ -202,6 +212,16 @@ srv_conc_enter_innodb_with_atomics(
+       for (;;) {
+               ulint   sleep_in_us;
++#ifdef WITH_WSREP
++              if (wsrep_on(trx->mysql_thd) && 
++                  wsrep_trx_is_aborting(trx->mysql_thd)) {
++                      if (wsrep_debug)
++                              fprintf(stderr, 
++                                      "srv_conc_enter due to MUST_ABORT");
++                      srv_conc_force_enter_innodb(trx);
++                      return;
++              }
++#endif /* WITH_WSREP */
+               if (srv_conc.n_active < (lint) srv_thread_concurrency) {
+                       ulint   n_active;
+@@ -319,6 +339,9 @@ srv_conc_exit_innodb_without_atomics(
+       slot = NULL;
+       if (srv_conc.n_active < (lint) srv_thread_concurrency) {
++#ifdef WITH_WSREP
++              srv_conc_slot_t*  wsrep_slot;
++#endif
+               /* Look for a slot where a thread is waiting and no other
+               thread has yet released the thread */
+@@ -329,6 +352,19 @@ srv_conc_exit_innodb_without_atomics(
+                       /* No op */
+               }
++#ifdef WITH_WSREP
++              /* look for aborting trx, they must be released asap */
++              wsrep_slot= slot;
++              while (wsrep_slot && (wsrep_slot->wait_ended == TRUE || 
++                  !wsrep_trx_is_aborting(wsrep_slot->thd))) {
++                      wsrep_slot = UT_LIST_GET_NEXT(srv_conc_queue, wsrep_slot);
++              }
++              if (wsrep_slot) {
++                      slot = wsrep_slot;
++                      if (wsrep_debug)
++                          fprintf(stderr, "WSREP: releasing aborting thd\n");
++              }
++#endif
+               if (slot != NULL) {
+                       slot->wait_ended = TRUE;
+@@ -384,6 +420,13 @@ retry:
+               return;
+       }
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd) && 
++          wsrep_trx_is_aborting(trx->mysql_thd)) {
++              srv_conc_force_enter_innodb(trx);
++              return;
++      }
++#endif
+       /* If the transaction is not holding resources, let it sleep
+       for srv_thread_sleep_delay microseconds, and try again then */
+@@ -450,6 +493,9 @@ retry:
+       /* Add to the queue */
+       slot->reserved = TRUE;
+       slot->wait_ended = FALSE;
++#ifdef WITH_WSREP
++      slot->thd = trx->mysql_thd;
++#endif
+       UT_LIST_ADD_LAST(srv_conc_queue, srv_conc_queue, slot);
+@@ -457,6 +503,18 @@ retry:
+       srv_conc.n_waiting++;
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd) && 
++          wsrep_trx_is_aborting(trx->mysql_thd)) {
++              os_fast_mutex_unlock(&srv_conc_mutex);
++              if (wsrep_debug)
++                      fprintf(stderr, "srv_conc_enter due to MUST_ABORT");
++              trx->declared_to_be_inside_innodb = TRUE;
++              trx->n_tickets_to_enter_innodb = srv_n_free_tickets_to_enter;
++              return;
++      }
++      trx->wsrep_event = slot->event;
++#endif /* WITH_WSREP */
+       os_fast_mutex_unlock(&srv_conc_mutex);
+       /* Go to wait for the event; when a thread leaves InnoDB it will
+@@ -471,6 +529,9 @@ retry:
+       thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
+       os_event_wait(slot->event);
++#ifdef WITH_WSREP
++      trx->wsrep_event = NULL;
++#endif /* WITH_WSREP */
+       thd_wait_end(trx->mysql_thd);
+       trx->op_info = "";
+@@ -483,6 +544,9 @@ retry:
+       incremented the thread counter on behalf of this thread */
+       slot->reserved = FALSE;
++#ifdef WITH_WSREP
++      slot->thd = NULL;
++#endif
+       UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot);
+@@ -593,5 +657,32 @@ srv_conc_get_active_threads(void)
+ /*==============================*/
+ {
+       return(srv_conc.n_active);
+- }
++}
++
++#ifdef WITH_WSREP
++UNIV_INTERN
++void
++wsrep_srv_conc_cancel_wait(
++/*==================*/
++      trx_t*  trx)    /*!< in: transaction object associated with the
++                      thread */
++{
++#ifdef HAVE_ATOMIC_BUILTINS
++      /* aborting transactions will enter innodb by force in 
++         srv_conc_enter_innodb_with_atomics(). No need to cancel here,
++         thr will wake up after os_sleep and let to enter innodb
++      */
++      if (wsrep_debug)
++              fprintf(stderr, "WSREP: conc slot cancel, no atomics\n");
++#else
++      os_fast_mutex_lock(&srv_conc_mutex);
++      if (trx->wsrep_event) {
++              if (wsrep_debug) 
++                      fprintf(stderr, "WSREP: conc slot cancel\n");
++              os_event_set(trx->wsrep_event);
++      }
++      os_fast_mutex_unlock(&srv_conc_mutex);
++#endif
++}
++#endif /* WITH_WSREP */
+diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
+index f4ea889..4404023 100644
+--- a/storage/innobase/srv/srv0srv.cc
++++ b/storage/innobase/srv/srv0srv.cc
+@@ -71,6 +71,10 @@ Created 10/8/1995 Heikki Tuuri
+ #include "mysql/plugin.h"
+ #include "mysql/service_thd_wait.h"
++#ifdef WITH_WSREP
++extern int wsrep_debug;
++extern int wsrep_trx_is_aborting(void *thd_ptr);
++#endif
+ /* The following is the maximum allowed duration of a lock wait. */
+ UNIV_INTERN ulint     srv_fatal_semaphore_wait_threshold = 600;
+@@ -207,6 +211,10 @@ srv_printf_innodb_monitor() will request mutex acquisition
+ with mutex_enter(), which will wait until it gets the mutex. */
+ #define MUTEX_NOWAIT(mutex_skipped)   ((mutex_skipped) < MAX_MUTEX_NOWAIT)
++#ifdef WITH_INNODB_DISALLOW_WRITES
++UNIV_INTERN os_event_t        srv_allow_writes_event;
++#endif /* WITH_INNODB_DISALLOW_WRITES */
++
+ /** The sort order table of the MySQL latin1_swedish_ci character set
+ collation */
+ UNIV_INTERN const byte*       srv_latin1_ordering;
+@@ -975,6 +983,14 @@ srv_init(void)
+       srv_conc_init();
++#ifdef WITH_INNODB_DISALLOW_WRITES
++      /* Writes have to be enabled on init or else we hang. Thus, we
++      always set the event here regardless of innobase_disallow_writes.
++      That flag will always be 0 at this point because it isn't settable
++      via my.cnf or command line arg. */
++      srv_allow_writes_event = os_event_create();
++      os_event_set(srv_allow_writes_event);
++#endif /* WITH_INNODB_DISALLOW_WRITES */
+       /* Initialize some INFORMATION SCHEMA internal structures */
+       trx_i_s_cache_init(trx_i_s_cache);
+@@ -1737,7 +1753,20 @@ loop:
+       if (sync_array_print_long_waits(&waiter, &sema)
+           && sema == old_sema && os_thread_eq(waiter, old_waiter)) {
++#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
++        if (srv_allow_writes_event->is_set) {
++#endif /* WITH_WSREP */
+               fatal_cnt++;
++#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
++        } else {
++              fprintf(stderr,
++                      "WSREP: avoiding InnoDB self crash due to long "
++                      "semaphore wait of  > %lu seconds\n"
++                      "Server is processing SST donor operation, "
++                      "fatal_cnt now: %lu",
++                      (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt);
++        }
++#endif /* WITH_WSREP */
+               if (fatal_cnt > 10) {
+                       fprintf(stderr,
+diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
+index bc11f1d..ae9095d 100644
+--- a/storage/innobase/trx/trx0roll.cc
++++ b/storage/innobase/trx/trx0roll.cc
+@@ -43,6 +43,9 @@ Created 3/26/1996 Heikki Tuuri
+ #include "row0mysql.h"
+ #include "lock0lock.h"
+ #include "pars0pars.h"
++#ifdef WITH_WSREP
++#include "ha_prototypes.h"
++#endif /* WITH_WSREP */
+ #include "srv0mon.h"
+ #include "trx0sys.h"
+@@ -374,6 +377,11 @@ trx_rollback_to_savepoint_for_mysql_low(
+       trx->op_info = "";
++#ifdef WITH_WSREP_OUT
++      if (wsrep_on(trx->mysql_thd)) {
++              trx->lock.was_chosen_as_deadlock_victim = FALSE;
++      }
++#endif /* WITH_WSREP */
+       return(err);
+ }
+@@ -1014,6 +1022,11 @@ trx_roll_try_truncate(
+       if (trx->update_undo) {
+               trx_undo_truncate_end(trx, trx->update_undo, limit);
+       }
++#ifdef WITH_WSREP_OUT
++      if (wsrep_on(trx->mysql_thd)) {
++              trx->lock.was_chosen_as_deadlock_victim = FALSE;
++      }
++#endif /* WITH_WSREP */
+ }
+ /***********************************************************************//**
+diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
+index 52830a7..816de1c 100644
+--- a/storage/innobase/trx/trx0sys.cc
++++ b/storage/innobase/trx/trx0sys.cc
+@@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri
+ #include "os0file.h"
+ #include "read0read.h"
++#ifdef WITH_WSREP
++#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */
++#endif /* */
++
+ /** The file format tag structure with id and name. */
+ struct file_format_t {
+       ulint           id;             /*!< id of the file format */
+@@ -174,7 +178,12 @@ trx_sys_flush_max_trx_id(void)
+       mtr_t           mtr;
+       trx_sysf_t*     sys_header;
++#ifndef WITH_WSREP
++      /* wsrep_fake_trx_id  violates this assert
++       * Copied from trx_sys_get_new_trx_id
++       */
+       ut_ad(mutex_own(&trx_sys->mutex));
++#endif /* WITH_WSREP */
+       if (!srv_read_only_mode) {
+               mtr_start(&mtr);
+@@ -202,10 +211,14 @@ trx_sys_update_mysql_binlog_offset(
+       ib_int64_t      offset, /*!< in: position in that log file */
+       ulint           field,  /*!< in: offset of the MySQL log info field in
+                               the trx sys header */
++#ifdef WITH_WSREP
++        trx_sysf_t*     sys_header, /*!< in: trx sys header */
++#endif /* WITH_WSREP */
+       mtr_t*          mtr)    /*!< in: mtr */
+ {
++#ifndef WITH_WSREP
+       trx_sysf_t*     sys_header;
+-
++#endif /* !WITH_WSREP */
+       if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
+               /* We cannot fit the name to the 512 bytes we have reserved */
+@@ -213,7 +226,9 @@ trx_sys_update_mysql_binlog_offset(
+               return;
+       }
++#ifndef WITH_WSREP
+       sys_header = trx_sysf_get(mtr);
++#endif /* !WITH_WSREP */
+       if (mach_read_from_4(sys_header + field
+                            + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
+@@ -300,6 +315,125 @@ trx_sys_print_mysql_binlog_offset(void)
+       mtr_commit(&mtr);
+ }
++#ifdef WITH_WSREP
++
++#ifdef UNIV_DEBUG
++static long long trx_sys_cur_xid_seqno = -1;
++static unsigned char trx_sys_cur_xid_uuid[16];
++
++long long read_wsrep_xid_seqno(const XID* xid)
++{
++    long long seqno;
++    memcpy(&seqno, xid->data + 24, sizeof(long long));
++    return seqno;
++}
++
++void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
++{
++    memcpy(buf, xid->data + 8, 16);
++}
++
++#endif /* UNIV_DEBUG */
++
++void
++trx_sys_update_wsrep_checkpoint(
++        const XID*      xid,        /*!< in: transaction XID */
++        trx_sysf_t*     sys_header, /*!< in: sys_header */
++        mtr_t*          mtr)        /*!< in: mtr */
++{
++
++#ifdef UNIV_DEBUG
++        {
++            /* Check that seqno is monotonically increasing */
++            unsigned char xid_uuid[16];
++            long long xid_seqno = read_wsrep_xid_seqno(xid);
++            read_wsrep_xid_uuid(xid, xid_uuid);
++            if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8))
++            {
++                ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
++                trx_sys_cur_xid_seqno = xid_seqno;
++            }
++            else
++            {
++                memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
++            }
++            trx_sys_cur_xid_seqno = xid_seqno;
++        }
++#endif /* UNIV_DEBUG */
++
++        ut_ad(xid && mtr && sys_header);
++        ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid));
++
++        if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
++                             + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
++            != TRX_SYS_WSREP_XID_MAGIC_N) {
++                mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
++                                 + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
++                                 TRX_SYS_WSREP_XID_MAGIC_N,
++                                 MLOG_4BYTES, mtr);
++        }
++
++        mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
++                         + TRX_SYS_WSREP_XID_FORMAT,
++                         (int)xid->formatID,
++                         MLOG_4BYTES, mtr);
++        mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
++                         + TRX_SYS_WSREP_XID_GTRID_LEN,
++                         (int)xid->gtrid_length,
++                         MLOG_4BYTES, mtr);
++        mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
++                         + TRX_SYS_WSREP_XID_BQUAL_LEN,
++                         (int)xid->bqual_length,
++                         MLOG_4BYTES, mtr);
++        mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
++                          + TRX_SYS_WSREP_XID_DATA,
++                          (const unsigned char*) xid->data,
++                          XIDDATASIZE, mtr);
++
++}
++
++void
++trx_sys_read_wsrep_checkpoint(XID* xid)
++/*===================================*/
++{
++        trx_sysf_t* sys_header;
++      mtr_t       mtr;
++        ulint       magic;
++
++        ut_ad(xid);
++
++      mtr_start(&mtr);
++
++      sys_header = trx_sysf_get(&mtr);
++
++        if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
++                                      + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
++            != TRX_SYS_WSREP_XID_MAGIC_N) {
++                memset(xid, 0, sizeof(*xid));
++                xid->formatID = -1;
++                trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
++                mtr_commit(&mtr);
++                return;
++        }
++
++        xid->formatID     = (int)mach_read_from_4(
++                sys_header
++                + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
++        xid->gtrid_length = (int)mach_read_from_4(
++                sys_header
++                + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
++        xid->bqual_length = (int)mach_read_from_4(
++                sys_header
++                + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
++        ut_memcpy(xid->data,
++                  sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
++                  XIDDATASIZE);
++
++      mtr_commit(&mtr);
++}
++
++#endif /* WITH_WSREP */
++
+ /*****************************************************************//**
+ Prints to stderr the MySQL master log offset info in the trx system header if
+ the magic number shows it valid. */
+diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
+index c2d5c1f..4c530dd 100644
+--- a/storage/innobase/trx/trx0trx.cc
++++ b/storage/innobase/trx/trx0trx.cc
+@@ -158,7 +158,10 @@ trx_create(void)
+       trx->lock.table_locks = ib_vector_create(
+               heap_alloc, sizeof(void**), 32);
+-      return(trx);
++#ifdef WITH_WSREP
++      trx->wsrep_event = NULL;
++#endif /* WITH_WSREP */
++      return(trx);
+ }
+ /********************************************************************//**
+@@ -853,6 +856,11 @@ trx_start_low(
+                       srv_undo_logs, srv_undo_tablespaces);
+       }
++#ifdef WITH_WSREP
++        memset(&trx->xid, 0, sizeof(trx->xid));
++        trx->xid.formatID = -1;
++#endif /* WITH_WSREP */
++
+       /* The initial value for trx->no: TRX_ID_MAX is used in
+       read_view_open_now: */
+@@ -967,6 +975,9 @@ trx_write_serialisation_history(
+       trx_t*          trx,    /*!< in/out: transaction */
+       mtr_t*          mtr)    /*!< in/out: mini-transaction */
+ {
++#ifdef WITH_WSREP
++        trx_sysf_t* sys_header;
++#endif /* WITH_WSREP */
+       trx_rseg_t*     rseg;
+       rseg = trx->rseg;
+@@ -1013,6 +1024,15 @@ trx_write_serialisation_history(
+       MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
++#ifdef WITH_WSREP
++        sys_header = trx_sysf_get(mtr);
++        /* Update latest MySQL wsrep XID in trx sys header. */
++        if (wsrep_is_wsrep_xid(&trx->xid))
++        {
++            trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr);
++        }
++#endif /* WITH_WSREP */
++
+       /* Update the latest MySQL binlog name and offset info
+       in trx sys header if MySQL binlogging is on or the database
+       server is a MySQL replication slave */
+@@ -1023,7 +1043,11 @@ trx_write_serialisation_history(
+               trx_sys_update_mysql_binlog_offset(
+                       trx->mysql_log_file_name,
+                       trx->mysql_log_offset,
++#ifdef WITH_WSREP
++                      TRX_SYS_MYSQL_LOG_INFO, sys_header, mtr);
++#else
+                       TRX_SYS_MYSQL_LOG_INFO, mtr);
++#endif /* WITH_WSREP */
+               trx->mysql_log_file_name = NULL;
+       }
+@@ -1318,6 +1342,11 @@ trx_commit_in_memory(
+       ut_ad(!trx->in_ro_trx_list);
+       ut_ad(!trx->in_rw_trx_list);
++#ifdef WITH_WSREP
++      if (wsrep_on(trx->mysql_thd)) {
++              trx->lock.was_chosen_as_deadlock_victim = FALSE;
++      }
++#endif
+       trx->dict_operation = TRX_DICT_OP_NONE;
+       trx->error_state = DB_SUCCESS;
+@@ -1502,6 +1531,10 @@ trx_commit_or_rollback_prepare(
+       switch (trx->state) {
+       case TRX_STATE_NOT_STARTED:
++#ifdef WITH_WSREP
++              ut_d(trx->start_file = __FILE__);
++              ut_d(trx->start_line = __LINE__);
++#endif /* WITH_WSREP */
+               trx_start_low(trx);
+               /* fall through */
+       case TRX_STATE_ACTIVE:
+@@ -2229,6 +2262,10 @@ trx_start_if_not_started_xa_low(
+               transaction, doesn't. */
+               trx->support_xa = thd_supports_xa(trx->mysql_thd);
++#ifdef WITH_WSREP
++              ut_d(trx->start_file = __FILE__);
++              ut_d(trx->start_line = __LINE__);
++#endif /* WITH_WSREP */
+               trx_start_low(trx);
+               /* fall through */
+       case TRX_STATE_ACTIVE:
+@@ -2251,6 +2288,10 @@ trx_start_if_not_started_low(
+ {
+       switch (trx->state) {
+       case TRX_STATE_NOT_STARTED:
++#ifdef WITH_WSREP
++              ut_d(trx->start_file = __FILE__);
++              ut_d(trx->start_line = __LINE__);
++#endif /* WITH_WSREP */
+               trx_start_low(trx);
+               /* fall through */
+       case TRX_STATE_ACTIVE:
+@@ -2284,6 +2325,10 @@ trx_start_for_ddl_low(
+               trx->will_lock = 1;
+               trx->ddl = true;
++#ifdef WITH_WSREP
++              ut_d(trx->start_file = __FILE__);
++              ut_d(trx->start_line = __LINE__);
++#endif /* WITH_WSREP */
+               trx_start_low(trx);
+               return;
+diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt
+index 5afe261..74b1075 100644
+--- a/support-files/CMakeLists.txt
++++ b/support-files/CMakeLists.txt
+@@ -93,4 +93,12 @@ IF(UNIX)
+     DESTINATION ${inst_location} COMPONENT SupportFiles
+     PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ 
+     GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
++  CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/wsrep_notify.sh 
++                 ${CMAKE_CURRENT_BINARY_DIR}/wsrep_notify @ONLY)
++  INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wsrep_notify
++    DESTINATION ${inst_location} COMPONENT SupportFiles
++    PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ 
++    GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
++  CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/wsrep.cnf.sh 
++                 ${CMAKE_CURRENT_BINARY_DIR}/wsrep.cnf @ONLY)
+ ENDIF()
+diff --git a/support-files/build-tags b/support-files/build-tags
+index c37485e..635940a 100755
+--- a/support-files/build-tags
++++ b/support-files/build-tags
+@@ -10,3 +10,7 @@ $list |grep $filter |while read f;
+ do
+        etags -o TAGS --append $f
+ done
++(cd storage/galera && svn ls -R) | grep $filter | while read f; 
++do
++      etags -o TAGS --append storage/galera/$f
++done 
+diff --git a/support-files/cmake-no-wix.patch b/support-files/cmake-no-wix.patch
+new file mode 100644
+index 0000000..325d97e
+--- /dev/null
++++ b/support-files/cmake-no-wix.patch
+@@ -0,0 +1,14 @@
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++index 9e235ba..15c3414 100644
++--- a/CMakeLists.txt
+++++ b/CMakeLists.txt
++@@ -569,7 +569,8 @@ IF(WIN32)
++ ELSE()
++   SET(CPACK_GENERATOR "TGZ")
++ ENDIF() 
++-ADD_SUBDIRECTORY(packaging/WiX)
+++# Trouble on SLES 11 due to old cmake ...
+++# ADD_SUBDIRECTORY(packaging/WiX)
++ ADD_SUBDIRECTORY(packaging/solaris)
++ 
++ # Create a single package with "make package"
+diff --git a/support-files/mysql-rpmlintrc b/support-files/mysql-rpmlintrc
+new file mode 100644
+index 0000000..72dd6e3
+--- /dev/null
++++ b/support-files/mysql-rpmlintrc
+@@ -0,0 +1,64 @@
++# allow the traditional name "mysql-shared" even with a so-versioned lib
++setBadness('shlib-policy-name-error', 0)
++
++# Suppress several "false positive" messages which we cannot prevent:
++# Oracle text we must not change:
++addFilter("MySQL.* invalid-license")
++addFilter("mysql.* invalid-license")
++addFilter("MySQL.* name-repeated-in-summary")
++addFilter("mysql.* name-repeated-in-summary")
++addFilter("MySQL.* no-version-in-last-changelog")
++addFilter("mysql.* no-version-in-last-changelog")
++addFilter("MySQL.*src.* invalid-spec-name")
++addFilter("mysql.*src.* invalid-spec-name")
++# Oracle code we must not change:
++addFilter("MySQL.*shared.* shared-lib-calls-exit /usr/lib64/libmysqlclient")
++addFilter("mysql.*shared.* shared-lib-calls-exit /usr/lib64/libmysqlclient")
++addFilter("MySQL.*server.* binary-or-shlib-calls-gethostbyname /usr/bin/resolveip")
++addFilter("mysql.*server.* binary-or-shlib-calls-gethostbyname /usr/bin/resolveip")
++# "obsolete" the Oracle commercial RPMs:
++addFilter("MySQL.* obsolete-not-provided mysql[^ ]*advanced")
++addFilter("mysql.* obsolete-not-provided mysql[^ ]*advanced")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*advanced")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*advanced")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*classic")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*classic")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*community")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*community")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*enterprise")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*enterprise")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*pro")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*pro")
++addFilter("MySQL.* obsolete-not-provided MySQL[^ ]*standard")
++addFilter("mysql.* obsolete-not-provided MySQL[^ ]*standard")
++# ... and the packages we dropped on intention:
++addFilter("MySQL.*devel.* obsolete-not-provided MySQL-embedded-devel")
++addFilter("mysql.*devel.* obsolete-not-provided MySQL-embedded-devel")
++addFilter("MySQL.*devel.* obsolete-not-provided mysql-embedded-devel")
++addFilter("mysql.*devel.* obsolete-not-provided mysql-embedded-devel")
++addFilter("MySQL.*test.* obsolete-not-provided MySQL-bench")
++addFilter("mysql.*test.* obsolete-not-provided MySQL-bench")
++addFilter("MySQL.*test.* obsolete-not-provided mysql-bench")
++addFilter("mysql.*test.* obsolete-not-provided mysql-bench")
++# Oracle does not strip binaries, and neither will we:
++addFilter("MySQL.* unstripped-binary-or-object /usr/s?bin/.*")
++addFilter("mysql.* unstripped-binary-or-object /usr/s?bin/.*")
++addFilter("MySQL.* unstripped-binary-or-object /usr/lib64/.*")
++addFilter("mysql.* unstripped-binary-or-object /usr/lib64/.*")
++addFilter("MySQL.*test.* unstripped-binary-or-object /usr/share/mysql-test/lib/.*")
++addFilter("mysql.*test.* unstripped-binary-or-object /usr/share/mysql-test/lib/.*")
++# Pre-defined certificates are needed for SSL tests, also a binary:
++addFilter("MySQL.*test.* pem-certificate")
++addFilter("mysql.*test.* pem-certificate")
++addFilter("MySQL.*test.* arch-dependent-file-in-usr-share /usr/share/mysql-test/lib/My/SafeProcess/my_safe_process")
++addFilter("mysql.*test.* arch-dependent-file-in-usr-share /usr/share/mysql-test/lib/My/SafeProcess/my_safe_process")
++# Oracle doesn't have a "check" section (yet):
++addFilter("MySQL.* make-check-outside-check-section")
++addFilter("mysql.* make-check-outside-check-section")
++# Documentation issues:
++addFilter("MySQL.*server.* no-manual-page-for-binary mysqld-debug")
++addFilter("mysql.*server.* no-manual-page-for-binary mysqld-debug")
++# File naming:
++addFilter("MySQL.*server.* incoherent-init-script-name mysql")
++addFilter("mysql.*server.* incoherent-init-script-name mysql")
++# End of the "false positive" messages which we cannot prevent.
+diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
+index 7487d5a..5c3f2f9 100644
+--- a/support-files/mysql.server.sh
++++ b/support-files/mysql.server.sh
+@@ -24,6 +24,11 @@
+ # Short-Description: start and stop MySQL
+ # Description: MySQL is a very fast and reliable SQL database engine.
+ ### END INIT INFO
++
++# Prevent OpenSUSE's init scripts from calling systemd, so that
++# both 'bootstrap' and 'start' are handled entirely within this script
++
++SYSTEMD_NO_WRAP=1
+  
+ # If you install MySQL on some other places than @prefix@, then you
+ # have to do one of the following things for this script to work:
+@@ -329,7 +334,10 @@ case "$mode" in
+     # Stop the service and regardless of whether it was
+     # running or not, start it again.
+     if $0 stop  $other_args; then
+-      $0 start $other_args
++      if ! $0 start $other_args; then
++        log_failure_msg "Failed to restart server."
++        exit 1
++      fi
+     else
+       log_failure_msg "Failed to stop running server, so refusing to try to start."
+       exit 1
+@@ -379,6 +387,12 @@ case "$mode" in
+       fi
+     fi
+     ;;
++    'bootstrap')
++      # Bootstrap the cluster, start the first node
++      # that initiate the cluster
++      echo $echo_n "Bootstrapping the cluster"
++      $0 start $other_args --wsrep-new-cluster
++      ;;
+     *)
+       # usage
+       basename=`basename "$0"`
+diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
+index c72ca39..9e8ce67 100644
+--- a/support-files/mysql.spec.sh
++++ b/support-files/mysql.spec.sh
+@@ -25,13 +25,15 @@
+ %global mysql_vendor            Oracle and/or its affiliates
+ %global mysql_version   @VERSION@
++%global wsrep_version   @WSREP_VERSION@
++%global wsrep_revision  @WSREP_REVISION@
+ %global mysqld_user     mysql
+ %global mysqld_group    mysql
+ %global mysqldatadir    /var/lib/mysql
+-%global release         1  
+-
++%global release         %{wsrep_version}
++%global short_product_tag 5.6
+ #
+ # Macros we use which are not available in all supported versions of RPM
+@@ -79,9 +81,9 @@
+ # Source name
+ # ----------------------------------------------------------------------------
+ %if %{undefined src_base}
+-%define src_base mysql
++%define src_base mysql-wsrep
+ %endif
+-%define src_dir %{src_base}-%{mysql_version}
++%define src_dir %{src_base}-%{mysql_version}-%{wsrep_version}
+ # ----------------------------------------------------------------------------
+ # Feature set (storage engines, options).  Default to community (everything)
+@@ -118,95 +120,48 @@
+ # ----------------------------------------------------------------------------
+ # Distribution support
+ # ----------------------------------------------------------------------------
+-%if %{undefined distro_specific}
+-%define distro_specific 0
++
++# Disable post build checks for time being.
++BuildConflicts: post-build-checks
++
++BuildRequires: gcc-c++ ncurses-devel perl zlib-devel cmake libaio-devel bison flex
++
++%if 0%{?rhel} == 6 || 0%{?rhel} == 7 || 0%{?fedora} == 20 || 0%{?fedora} == 21
++BuildRequires: time
+ %endif
+-%if %{distro_specific}
+-  %if %(test -f /etc/enterprise-release && echo 1 || echo 0)
+-    %define oelver %(rpm -qf --qf '%%{version}\\n' /etc/enterprise-release | sed -e 's/^\\([0-9]*\\).*/\\1/g')
+-    %if "%oelver" == "4"
+-      %define distro_description        Oracle Enterprise Linux 4
+-      %define distro_releasetag         oel4
+-      %define distro_buildreq           gcc-c++ gperf ncurses-devel perl time zlib-devel cmake libaio-devel
+-      %define distro_requires           chkconfig coreutils grep procps shadow-utils net-tools
+-    %else
+-      %if "%oelver" == "5"
+-        %define distro_description      Oracle Enterprise Linux 5
+-        %define distro_releasetag       oel5
+-        %define distro_buildreq         gcc-c++ gperf ncurses-devel perl time zlib-devel cmake libaio-devel
+-        %define distro_requires         chkconfig coreutils grep procps shadow-utils net-tools
+-      %else
+-        %{error:Oracle Enterprise Linux %{oelver} is unsupported}
+-      %endif
+-    %endif
+-  %else
+-    %if %(test -f /etc/oracle-release && echo 1 || echo 0)
+-      %define elver %(rpm -qf --qf '%%{version}\\n' /etc/oracle-release | sed -e 's/^\\([0-9]*\\).*/\\1/g')
+-      %if "%elver" == "6" || "%elver" == "7"
+-        %define distro_description      Oracle Linux %elver
+-        %define distro_releasetag       el%elver
+-        %define distro_buildreq         gcc-c++ ncurses-devel perl time zlib-devel cmake libaio-devel
+-        %define distro_requires         chkconfig coreutils grep procps shadow-utils net-tools
+-      %else
+-        %{error:Oracle Linux %{elver} is unsupported}
+-      %endif
+-    %else
+-      %if %(test -f /etc/redhat-release && echo 1 || echo 0)
+-        %define rhelver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g')
+-        %if "%rhelver" == "4"
+-          %define distro_description      Red Hat Enterprise Linux 4
+-          %define distro_releasetag       rhel4
+-          %define distro_buildreq         gcc-c++ gperf ncurses-devel perl time zlib-devel cmake libaio-devel
+-          %define distro_requires         chkconfig coreutils grep procps shadow-utils net-tools
+-        %else
+-          %if "%rhelver" == "5"
+-            %define distro_description    Red Hat Enterprise Linux 5
+-            %define distro_releasetag     rhel5
+-            %define distro_buildreq       gcc-c++ gperf ncurses-devel perl time zlib-devel cmake libaio-devel
+-            %define distro_requires       chkconfig coreutils grep procps shadow-utils net-tools
+-          %else
+-            %if "%rhelver" == "6"
+-              %define distro_description    Red Hat Enterprise Linux 6
+-              %define distro_releasetag     rhel6
+-              %define distro_buildreq       gcc-c++ ncurses-devel perl time zlib-devel cmake libaio-devel
+-              %define distro_requires       chkconfig coreutils grep procps shadow-utils net-tools
+-            %else
+-              %{error:Red Hat Enterprise Linux %{rhelver} is unsupported}
+-            %endif
+-          %endif
+-        %endif
+-      %else
+-        %if %(test -f /etc/SuSE-release && echo 1 || echo 0)
+-          %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release | cut -d. -f1)
+-          %if "%susever" == "10"
+-            %define distro_description    SUSE Linux Enterprise Server 10
+-            %define distro_releasetag     sles10
+-            %define distro_buildreq       gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client zlib-devel cmake libaio-devel
+-            %define distro_requires       aaa_base coreutils grep procps pwdutils
+-          %else
+-            %if "%susever" == "11"
+-              %define distro_description  SUSE Linux Enterprise Server 11
+-              %define distro_releasetag   sles11
+-              %define distro_buildreq     gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client procps pwdutils zlib-devel cmake libaio-devel
+-              %define distro_requires     aaa_base coreutils grep procps pwdutils
+-            %else
+-              %{error:SuSE %{susever} is unsupported}
+-            %endif
+-          %endif
+-        %else
+-          %{error:Unsupported distribution}
+-        %endif
+-      %endif
+-    %endif
++
++%if 0%{?suse_version}
++%if 0%{?suse_version} == 1110
++BuildRequires: gdbm-devel gperf openldap2-client procps pwdutils
++%endif
++%if 0%{?suse_version} == 1310 || 0%{?suse_version} == 1315 || 0%{?suse_version} == 1320
++BuildRequires: gperf procps time
++%endif
++%endif
++
++# Define dist tag if not given by platform
++%if %{undefined dist}
++  # For suse versions see:
++  # https://en.opensuse.org/openSUSE:Build_Service_cross_distribution_howto
++  %if 0%{?suse_version} == 1110
++    %define dist .sle11
++  %endif
++  %if 0%{?suse_version} == 1310
++    %define dist .suse13.1
++  %endif
++  %if 0%{?suse_version} == 1315
++    %define dist .sle12
++  %endif
++  %if 0%{?suse_version} == 1320
++    %define dist .suse13.2
++  %endif
++  # Still missing?
++  %if %{undefined dist}
++    %define dist .DIST
+   %endif
+-%else
+-  %define glibc_version %(/lib/libc.so.6 | grep stable | cut -d, -f1 | cut -c38-)
+-  %define distro_description            Generic Linux (glibc %{glibc_version})
+-  %define distro_releasetag             linux_glibc%{glibc_version}
+-  %define distro_buildreq               gcc-c++ gperf ncurses-devel perl  time zlib-devel
+-  %define distro_requires               coreutils grep procps /sbin/chkconfig /usr/sbin/useradd /usr/sbin/groupadd
+ %endif
++
+ # Avoid debuginfo RPMs, leaves binaries unstripped
+ %define debug_package   %{nil}
+@@ -231,7 +186,7 @@
+ %define license_files_server    %{src_dir}/LICENSE.mysql
+ %define license_type            Commercial
+ %else
+-%define license_files_server    %{src_dir}/COPYING %{src_dir}/README
++%define license_files_server    COPYING README
+ %define license_type            GPL
+ %endif
+@@ -243,17 +198,20 @@ Name:           MySQL%{product_suffix}
+ Summary:        MySQL: a very fast and reliable SQL database server
+ Group:          Applications/Databases
+ Version:        @MYSQL_RPM_VERSION@
+-Release:        %{release}%{?distro_releasetag:.%{distro_releasetag}}
+-Distribution:   %{distro_description}
++Release:        %{release}%{dist}
++# Distribution:   %{distro_description}
+ License:        Copyright (c) 2000, @MYSQL_COPYRIGHT_YEAR@, %{mysql_vendor}. All rights reserved. Under %{license_type} license as shown in the Description field.
+-Source:         http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/%{src_dir}.tar.gz
++Source:         %{src_dir}.tar.gz
++Source99:       mysql-rpmlintrc
++Patch0:          cmake-no-wix.patch
+ URL:            http://www.mysql.com/
+-Packager:       MySQL Release Engineering <mysql-build@oss.oracle.com> 
++Packager:       Codership Oy <info@galeracluster.com>
+ Vendor:         %{mysql_vendor}
+-BuildRequires:  %{distro_buildreq}
++# BuildRequires:  %{distro_buildreq}
++#wsrep_patch_tag
+ # Regression tests may take a long time, override the default to skip them 
+-%{!?runselftest:%global runselftest 1}
++%{!?runselftest:%global runselftest 0}
+ # Think about what you use here since the first step is to
+ # run a rm -rf
+@@ -282,10 +240,41 @@ documentation and the manual for more information.
+ # Sub package definition
+ ##############################################################################
+-%package -n MySQL-server%{product_suffix}
++%package -n mysql-wsrep%{product_suffix}
++Summary:        MySQL: meta package for a server+client setup
++Group:          Applications/Databases
++Requires:       mysql-wsrep-server%{product_suffix}
++Requires:       mysql-wsrep-client%{product_suffix}
++
++%description -n mysql-wsrep%{product_suffix}
++This meta package ensures the installation of a MySQL server and the necessary
++client programs for operation and administration. It does not itself
++contain those files but rather causes the installation of the subpackages
++"mysql-wsrep-server%{product_suffix}" and "mysql-wsrep-client%{product_suffix}".
++As indicated in the name, the server is built with the "wsrep" plugin so that
++it can be a node in a MySQL Galera Cluster.
++
++# ----------------------------------------------------------------------------
++
++%package -n mysql-wsrep-server%{product_suffix}
+ Summary:        MySQL: a very fast and reliable SQL database server
+ Group:          Applications/Databases
+-Requires:       %{distro_requires}
++# Distro requirements
++# RedHat
++%if 0%{?fedora} || 0%{?rhel}
++Requires:       chkconfig coreutils grep procps shadow-utils net-tools rsync lsof
++%if 0%{?rhel} == 7 || 0%{?fedora} >= 20
++Requires: perl-Data-Dumper
++%endif
++%endif
++# SUSE
++%if 0%{?suse_version}
++Requires: aaa_base coreutils grep procps rsync lsof
++%if 0%{suse_version} == 1110
++Requires: pwdutils
++%endif
++%endif
++
+ %if 0%{?commercial}
+ Obsoletes:      MySQL-server
+ %else
+@@ -298,7 +287,7 @@ Obsoletes:      MySQL-server-advanced-gpl MySQL-server-enterprise-gpl
+ Provides:       mysql-server = %{version}-%{release}
+ Provides:       mysql-server%{?_isa} = %{version}-%{release}
+-%description -n MySQL-server%{product_suffix}
++%description -n mysql-wsrep-server%{product_suffix}
+ The MySQL(TM) software delivers a very fast, multi-threaded, multi-user,
+ and robust SQL (Structured Query Language) database server. MySQL Server
+ is intended for mission-critical, heavy-load production systems as well
+@@ -319,11 +308,13 @@ and the manual for more information.
+ This package includes the MySQL server binary as well as related utilities
+ to run and administer a MySQL server.
++Built with wsrep patch %{wsrep_version}.
++
+ If you want to access and work with the database, you have to install
+-package "MySQL-client%{product_suffix}" as well!
++package "mysql-wsrep-client%{product_suffix}" as well!
+ # ----------------------------------------------------------------------------
+-%package -n MySQL-client%{product_suffix}
++%package -n mysql-wsrep-client%{product_suffix}
+ Summary:        MySQL - Client
+ Group:          Applications/Databases
+ %if 0%{?commercial}
+@@ -338,13 +329,13 @@ Obsoletes:      MySQL-client-advanced-gpl MySQL-client-enterprise-gpl
+ Provides:       mysql = %{version}-%{release} 
+ Provides:       mysql%{?_isa} = %{version}-%{release}
+-%description -n MySQL-client%{product_suffix}
++%description -n mysql-wsrep-client%{product_suffix}
+ This package contains the standard MySQL clients and administration tools.
+ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+ # ----------------------------------------------------------------------------
+-%package -n MySQL-test%{product_suffix}
++%package -n mysql-wsrep-test%{product_suffix}
+ Summary:        MySQL - Test suite
+ Group:          Applications/Databases
+ %if 0%{?commercial}
+@@ -362,13 +353,13 @@ Provides:       mysql-test = %{version}-%{release}
+ Provides:       mysql-test%{?_isa} = %{version}-%{release}
+ AutoReqProv:    no
+-%description -n MySQL-test%{product_suffix}
++%description -n mysql-wsrep-test%{product_suffix}
+ This package contains the MySQL regression test suite.
+ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+ # ----------------------------------------------------------------------------
+-%package -n MySQL-devel%{product_suffix}
++%package -n mysql-wsrep-devel%{product_suffix}
+ Summary:        MySQL - Development header files and libraries
+ Group:          Applications/Databases
+ %if 0%{?commercial}
+@@ -383,14 +374,14 @@ Obsoletes:      MySQL-devel-advanced-gpl MySQL-devel-enterprise-gpl
+ Provides:       mysql-devel = %{version}-%{release}
+ Provides:       mysql-devel%{?_isa} = %{version}-%{release}
+-%description -n MySQL-devel%{product_suffix}
++%description -n mysql-wsrep-devel%{product_suffix}
+ This package contains the development header files and libraries necessary
+ to develop MySQL client applications.
+ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+ # ----------------------------------------------------------------------------
+-%package -n MySQL-shared%{product_suffix}
++%package -n mysql-wsrep-shared%{product_suffix}
+ Summary:        MySQL - Shared libraries
+ Group:          Applications/Databases
+ %if 0%{?commercial}
+@@ -404,44 +395,17 @@ Obsoletes:      MySQL-shared-pro-gpl-cert
+ Obsoletes:      MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise
+ Obsoletes:      MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl
+-%description -n MySQL-shared%{product_suffix}
++%description -n mysql-wsrep-shared%{product_suffix}
+ This package contains the shared libraries (*.so*) which certain languages
+ and applications need to dynamically load and use MySQL.
+-# ----------------------------------------------------------------------------
+-%package -n MySQL-embedded%{product_suffix}
+-Summary:        MySQL - Embedded library
+-Group:          Applications/Databases
+-%if 0%{?commercial}
+-Requires:       MySQL-devel-advanced
+-Obsoletes:      MySQL-embedded
+-%else
+-Requires:       MySQL-devel
+-Obsoletes:      MySQL-embedded-advanced
+-%endif
+-Obsoletes:      mysql-embedded < %{version}-%{release}
+-Obsoletes:      mysql-embedded-advanced
+-Obsoletes:      MySQL-embedded-pro
+-Obsoletes:      MySQL-embedded-classic MySQL-embedded-community MySQL-embedded-enterprise
+-Obsoletes:      MySQL-embedded-advanced-gpl MySQL-embedded-enterprise-gpl
+-Provides:       mysql-embedded = %{version}-%{release}
+-Provides:       mysql-emdedded%{?_isa} = %{version}-%{release}
+-
+-%description -n MySQL-embedded%{product_suffix}
+-This package contains the MySQL server as an embedded library.
+-
+-The embedded MySQL server library makes it possible to run a full-featured
+-MySQL server inside the client application. The main benefits are increased
+-speed and more simple management for embedded applications.
+-
+-The API is identical for the embedded MySQL version and the
+-client/server version.
+-
+-For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+-
+ ##############################################################################
+ %prep
+-%setup -T -a 0 -c -n %{src_dir}
++%setup -n %{src_dir}
++# That patch is needed with old cmake only, on SLES 11, but it won't do any harm
++# outside Windows, so it may be used in all RPM builds.
++%patch0 -p1
++#wsrep_apply_patch_tag
+ ##############################################################################
+ %build
+@@ -481,7 +445,7 @@ export CFLAGS=${MYSQL_BUILD_CFLAGS:-${CFLAGS:-$RPM_OPT_FLAGS}}
+ export CXXFLAGS=${MYSQL_BUILD_CXXFLAGS:-${CXXFLAGS:-$RPM_OPT_FLAGS -felide-constructors}}
+ export LDFLAGS=${MYSQL_BUILD_LDFLAGS:-${LDFLAGS:-}}
+ export CMAKE=${MYSQL_BUILD_CMAKE:-${CMAKE:-cmake}}
+-export MAKE_JFLAG=${MYSQL_BUILD_MAKE_JFLAG:-}
++export MAKE_JFLAG=${MYSQL_BUILD_MAKE_JFLAG:--j$(ncpu=$(cat /proc/cpuinfo | grep processor | wc -l) && echo $(($ncpu > 4 ? 4 : $ncpu)))}
+ # By default, a build will include the bundeled "yaSSL" library for SSL.
+ # However, there may be a need to override.
+@@ -500,6 +464,7 @@ mkdir debug
+   CFLAGS=`echo " ${CFLAGS} " | \
+             sed -e 's/ -O[0-9]* / /' \
+                 -e 's/-Wp,-D_FORTIFY_SOURCE=2/ /' \
++                -e 's/-D_FORTIFY_SOURCE=2/ /' \
+                 -e 's/ -unroll2 / /' \
+                 -e 's/ -ip / /' \
+                 -e 's/^ //' \
+@@ -507,19 +472,23 @@ mkdir debug
+   CXXFLAGS=`echo " ${CXXFLAGS} " | \
+               sed -e 's/ -O[0-9]* / /' \
+                   -e 's/-Wp,-D_FORTIFY_SOURCE=2/ /' \
++                  -e 's/-D_FORTIFY_SOURCE=2/ /' \
+                   -e 's/ -unroll2 / /' \
+                   -e 's/ -ip / /' \
+                   -e 's/^ //' \
+                   -e 's/ $//'`
+   # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before
+   # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM
+-  ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
++  ${CMAKE} ../ -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
+            -DCMAKE_BUILD_TYPE=Debug \
+            -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
+            -DFEATURE_SET="%{feature_set}" \
+            %{ssl_option} \
+            -DCOMPILATION_COMMENT="%{compilation_comment_debug}" \
+-           -DMYSQL_SERVER_SUFFIX="%{server_suffix}"
++           -DMYSQL_SERVER_SUFFIX="%{server_suffix}" \
++           -DWITH_WSREP=1 \
++           -DWSREP_VERSION="%{wsrep_version}" \
++           -DWSREP_REVISION="%{wsrep_revision}"
+   echo BEGIN_DEBUG_CONFIG ; egrep '^#define' include/config.h ; echo END_DEBUG_CONFIG
+   make ${MAKE_JFLAG} VERBOSE=1
+ )
+@@ -529,13 +498,16 @@ mkdir release
+   cd release
+   # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before
+   # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM
+-  ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
++  ${CMAKE} ../ -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
+            -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+            -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
+            -DFEATURE_SET="%{feature_set}" \
+            %{ssl_option} \
+            -DCOMPILATION_COMMENT="%{compilation_comment_release}" \
+-           -DMYSQL_SERVER_SUFFIX="%{server_suffix}"
++           -DMYSQL_SERVER_SUFFIX="%{server_suffix}" \
++           -DWITH_WSREP=1 \
++           -DWSREP_VERSION="%{wsrep_version}" \
++           -DWSREP_REVISION="%{wsrep_revision}"
+   echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG
+   make ${MAKE_JFLAG} VERBOSE=1
+ )
+@@ -582,14 +554,20 @@ install -m 755 $MBD/release/support-files/mysql.server $RBR%{_sysconfdir}/init.d
+ # Create a symlink "rcmysql", pointing to the init.script. SuSE users
+ # will appreciate that, as all services usually offer this.
+-ln -s %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql
++ln -sf %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql
++
++# Create a wsrep_sst_rsync_wan symlink.
++install -d $RBR%{_bindir}
++ln -sf wsrep_sst_rsync $RBR%{_bindir}/wsrep_sst_rsync_wan
+ # Touch the place where the my.cnf config file might be located
+ # Just to make sure it's in the file list and marked as a config file
+ touch $RBR%{_sysconfdir}/my.cnf
++touch $RBR%{_sysconfdir}/wsrep.cnf
++
+ # Install SELinux files in datadir
+-install -m 600 $MBD/%{src_dir}/support-files/RHEL4-SElinux/mysql.{fc,te} \
++install -m 600 $MBD/support-files/RHEL4-SElinux/mysql.{fc,te} \
+   $RBR%{_datadir}/mysql/SELinux/RHEL4
+ %if %{WITH_TCMALLOC}
+@@ -608,7 +586,7 @@ install -m 644 "%{malloc_lib_source}" \
+ #  Post processing actions, i.e. when installed
+ ##############################################################################
+-%pre -n MySQL-server%{product_suffix}
++%pre -n mysql-wsrep-server%{product_suffix}
+ # This is the code running at the beginning of a RPM upgrade action,
+ # before replacing the old files with the new ones.
+@@ -786,7 +764,7 @@ if [ -x %{_sysconfdir}/init.d/mysql ] ; then
+         sleep 5
+ fi
+-%post -n MySQL-server%{product_suffix}
++%post -n mysql-wsrep-server%{product_suffix}
+ # This is the code running at the end of a RPM install or upgrade action,
+ # after the (new) files have been written.
+@@ -946,7 +924,7 @@ mv -f  $STATUS_FILE ${STATUS_FILE}-LAST  # for "triggerpostun"
+ #scheduled service packs and more.  Visit www.mysql.com/enterprise for more
+ #information."
+-%preun -n MySQL-server%{product_suffix}
++%preun -n mysql-wsrep-server%{product_suffix}
+ # Which '$1' does this refer to?  Fedora docs have info:
+ # " ... a count of the number of versions of the package that are installed.
+@@ -975,7 +953,7 @@ fi
+ # We do not remove the mysql user since it may still own a lot of
+ # database files.
+-%triggerpostun -n MySQL-server%{product_suffix} --MySQL-server-community
++%triggerpostun -n mysql-wsrep-server%{product_suffix} --MySQL-server-community
+ # Setup: We renamed this package, so any existing "server-community"
+ #   package will be removed when this "server" is installed.
+@@ -1046,15 +1024,22 @@ echo "====="                                     >> $STATUS_HISTORY
+ #  Files section
+ ##############################################################################
+-%files -n MySQL-server%{product_suffix} -f release/support-files/plugins.files
++%files -n mysql-wsrep%{product_suffix}
++# Intentionally empty - this is a pure meta package.
++
++# ----------------------------------------------------------------------------
++%files -n mysql-wsrep-server%{product_suffix} -f release/support-files/plugins.files
+ %defattr(-,root,root,0755)
+ %if %{defined license_files_server}
+ %doc %{license_files_server}
+ %endif
+-%doc %{src_dir}/Docs/ChangeLog
+-%doc %{src_dir}/Docs/INFO_SRC*
++%doc Docs/ChangeLog
++%doc release/Docs/INFO_SRC*
+ %doc release/Docs/INFO_BIN*
+ %doc release/support-files/my-default.cnf
++%doc Docs/README-wsrep
++%doc release/support-files/wsrep.cnf
++%doc release/support-files/wsrep_notify
+ %if 0%{?commercial}
+ %doc %attr(644, root, root) %{_infodir}/mysql.info*
+@@ -1090,6 +1075,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ %doc %attr(644, root, man) %{_mandir}/man1/resolveip.1*
+ %ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf
++%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf
+ %dir %{_sysconfdir}/my.cnf.d
+ %attr(755, root, root) %{_bindir}/innochecksum
+@@ -1117,10 +1103,18 @@ echo "====="                                     >> $STATUS_HISTORY
+ %attr(755, root, root) %{_bindir}/replace
+ %attr(755, root, root) %{_bindir}/resolve_stack_dump
+ %attr(755, root, root) %{_bindir}/resolveip
++%attr(755, root, root) %{_bindir}/wsrep_sst_common
++%attr(755, root, root) %{_bindir}/wsrep_sst_mysqldump
++%attr(755, root, root) %{_bindir}/wsrep_sst_rsync
++%attr(755, root, root) %{_bindir}/wsrep_sst_rsync_wan
++%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup
++%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup-v2
+ %attr(755, root, root) %{_sbindir}/mysqld
+ %attr(755, root, root) %{_sbindir}/mysqld-debug
+ %attr(755, root, root) %{_sbindir}/rcmysql
++%dir %{_libdir}/mysql/plugin
++%dir %{_libdir}/mysql/plugin/debug
+ %attr(755, root, root) %{_libdir}/mysql/plugin/daemon_example.ini
+ %if %{WITH_TCMALLOC}
+@@ -1133,7 +1127,8 @@ echo "====="                                     >> $STATUS_HISTORY
+ %dir %attr(755, mysql, mysql) /var/lib/mysql
+ # ----------------------------------------------------------------------------
+-%files -n MySQL-client%{product_suffix}
++%files -n mysql-wsrep-client%{product_suffix}
++
+ %defattr(-, root, root, 0755)
+ %if %{defined license_files_server}
+ %doc %{license_files_server}
+@@ -1169,7 +1164,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ %doc %attr(644, root, man) %{_mandir}/man1/mysql_config_editor.1*
+ # ----------------------------------------------------------------------------
+-%files -n MySQL-devel%{product_suffix} -f optional-files-devel
++%files -n mysql-wsrep-devel%{product_suffix} -f optional-files-devel
+ %defattr(-, root, root, 0755)
+ %if %{defined license_files_server}
+ %doc %{license_files_server}
+@@ -1186,7 +1181,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ %{_libdir}/mysql/libmysqlservices.a
+ # ----------------------------------------------------------------------------
+-%files -n MySQL-shared%{product_suffix}
++%files -n mysql-wsrep-shared%{product_suffix}
+ %defattr(-, root, root, 0755)
+ %if %{defined license_files_server}
+ %doc %{license_files_server}
+@@ -1194,44 +1189,47 @@ echo "====="                                     >> $STATUS_HISTORY
+ # Shared libraries (omit for architectures that don't support them)
+ %{_libdir}/libmysql*.so*
+-%post -n MySQL-shared%{product_suffix}
++%post -n mysql-wsrep-shared%{product_suffix}
+ /sbin/ldconfig
+-%postun -n MySQL-shared%{product_suffix}
++%postun -n mysql-wsrep-shared%{product_suffix}
+ /sbin/ldconfig
+ # ----------------------------------------------------------------------------
+-%files -n MySQL-test%{product_suffix}
++%files -n mysql-wsrep-test%{product_suffix}
+ %defattr(-, root, root, 0755)
+ %if %{defined license_files_server}
+ %doc %{license_files_server}
+ %endif
+ %attr(-, root, root) %{_datadir}/mysql-test
+ %attr(755, root, root) %{_bindir}/mysql_client_test
+-%attr(755, root, root) %{_bindir}/mysql_client_test_embedded
+-%attr(755, root, root) %{_bindir}/mysqltest_embedded
+ %doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test.1*
+ %doc %attr(644, root, man) %{_mandir}/man1/mysql-stress-test.pl.1*
+ %doc %attr(644, root, man) %{_mandir}/man1/mysql-test-run.pl.1*
+ %doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test_embedded.1*
+ %doc %attr(644, root, man) %{_mandir}/man1/mysqltest_embedded.1*
+-# ----------------------------------------------------------------------------
+-%files -n MySQL-embedded%{product_suffix}
+-%defattr(-, root, root, 0755)
+-%if %{defined license_files_server}
+-%doc %{license_files_server}
+-%endif
+-%attr(755, root, root) %{_bindir}/mysql_embedded
+-%attr(644, root, root) %{_libdir}/mysql/libmysqld.a
+-%attr(644, root, root) %{_libdir}/mysql/libmysqld-debug.a
+-
+ ##############################################################################
+ # The spec file changelog only includes changes made to the spec file
+ # itself - note that they must be ordered by date (important when
+ # merging BK trees)
+ ##############################################################################
+ %changelog
++* Thu Jan 29 2015 Joerg Bruehe <joerg.bruehe@fromdual.com>
++- Add a meta-package "mysql-wsrep" that requires both "server" and "client".
++- Fix the fall-back definition of "dist", it must start with a period.
++
++* Mon Jan 26 2015 Joerg Bruehe <joerg.bruehe@fromdual.com>
++- Allow "rpmlint", but suppress "post-build-checks" (fail on SuSE 12 + 13).
++- Improve handling of undefined "%%{dist}".
++- Fix wrong changelog dates, to get rid of warnings about "bogus date".
++- Escape percent signs in changelog, to get rid of "rpmlint" warnings.
++
++* Tue Jan 20 2015 Teemu Ollakka <teemu.ollakka@galeracluster.com>
++
++- Reworked to build wsrep patched packages exclusively
++- OBS compatible
++
+ * Mon Oct 06 2014 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+ - Add license info in each subpackage
+@@ -1350,7 +1348,7 @@ echo "====="                                     >> $STATUS_HISTORY
+   not in an RPM upgrade.
+   This affects both the "mkdir" and the call of "mysql_install_db".
+-* Wed Feb 09 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
++* Thu Feb 10 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+ - Fix bug#56581: If an installation deviates from the default file locations
+   ("datadir" and "pid-file"), the mechanism to detect a running server (on upgrade)
+@@ -1471,7 +1469,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ - Fix some problems with the directives around "tcmalloc" (experimental),
+   remove erroneous traces of the InnoDB plugin (that is 5.1 only).
+-* Tue Oct 06 2009 Magnus Blaudd <mvensson@mysql.com>
++* Fri Oct 09 2009 Magnus Blaudd <mvensson@mysql.com>
+ - Removed mysql_fix_privilege_tables
+@@ -1668,7 +1666,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ - Set $LDFLAGS from $MYSQL_BUILD_LDFLAGS
+-* Tue Mar 07 2006 Kent Boortz <kent@mysql.com>
++* Wed Mar 08 2006 Kent Boortz <kent@mysql.com>
+ - Changed product name from "Community Edition" to "Community Server"
+@@ -1763,7 +1761,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ * Thu Sep 29 2005 Lenz Grimmer <lenz@mysql.com>
+-- fixed the removing of the RPM_BUILD_ROOT in the %clean section (the
++- fixed the removing of the RPM_BUILD_ROOT in the %%clean section (the
+   $RBR variable did not get expanded, thus leaving old build roots behind)
+ * Thu Aug 04 2005 Lenz Grimmer <lenz@mysql.com>
+@@ -1916,7 +1914,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ - marked /etc/logrotate.d/mysql as a config file (BUG 2156)
+-* Sat Dec 13 2003 Lenz Grimmer <lenz@mysql.com>
++* Fri Dec 12 2003 Lenz Grimmer <lenz@mysql.com>
+ - fixed file permissions (BUG 1672)
+@@ -2058,7 +2056,7 @@ echo "====="                                     >> $STATUS_HISTORY
+ - Added separate libmysql_r directory; now both a threaded
+   and non-threaded library is shipped.
+-* Tue Sep 28 1999 David Axmark <davida@mysql.com>
++* Wed Sep 29 1999 David Axmark <davida@mysql.com>
+ - Added the support-files/my-example.cnf to the docs directory.
+diff --git a/support-files/wsrep.cnf b/support-files/wsrep.cnf
+new file mode 100644
+index 0000000..756d4f6
+--- /dev/null
++++ b/support-files/wsrep.cnf
+@@ -0,0 +1,129 @@
++# This file contains wsrep-related mysqld options. It should be included
++# in the main MySQL configuration file.
++#
++# Options that need to be customized:
++#  - wsrep_provider
++#  - wsrep_cluster_address
++#  - wsrep_sst_auth
++# The rest of defaults should work out of the box.
++
++##
++## mysqld options _MANDATORY_ for correct opration of the cluster
++##
++[mysqld]
++
++# (This must be substituted by wsrep_format)
++binlog_format=ROW
++
++# Currently only InnoDB storage engine is supported
++default-storage-engine=innodb
++
++# to avoid issues with 'bulk mode inserts' using autoinc
++innodb_autoinc_lock_mode=2
++
++# This is a must for paralell applying
++innodb_locks_unsafe_for_binlog=1
++
++# Query Cache is not supported with wsrep
++query_cache_size=0
++query_cache_type=0
++
++# Override bind-address
++# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST
++# it will have (most likely) disastrous consequences on donor node
++bind-address=0.0.0.0
++
++##
++## WSREP options
++##
++
++# Full path to wsrep provider library or 'none'
++wsrep_provider=none
++
++# Provider specific configuration options
++#wsrep_provider_options=
++
++# Logical cluster name. Should be the same for all nodes.
++wsrep_cluster_name="my_wsrep_cluster"
++
++# Group communication system handle
++#wsrep_cluster_address="dummy://"
++
++# Human-readable node name (non-unique). Hostname by default.
++#wsrep_node_name=
++
++# Base replication <address|hostname>[:port] of the node.
++# The values supplied will be used as defaults for state transfer receiving,
++# listening ports and so on. Default: address of the first network interface.
++#wsrep_node_address=
++
++# Address for incoming client connections. Autodetect by default.
++#wsrep_node_incoming_address=
++
++# How many threads will process writesets from other nodes
++wsrep_slave_threads=1
++
++# DBUG options for wsrep provider
++#wsrep_dbug_option
++
++# Generate fake primary keys for non-PK tables (required for multi-master
++# and parallel applying operation)
++wsrep_certify_nonPK=1
++
++# Maximum number of rows in write set
++wsrep_max_ws_rows=131072
++
++# Maximum size of write set
++wsrep_max_ws_size=1073741824
++
++# to enable debug level logging, set this to 1
++wsrep_debug=0
++
++# convert locking sessions into transactions
++wsrep_convert_LOCK_to_trx=0
++
++# how many times to retry deadlocked autocommits
++wsrep_retry_autocommit=1
++
++# change auto_increment_increment and auto_increment_offset automatically
++wsrep_auto_increment_control=1
++
++# retry autoinc insert, which failed for duplicate key error
++wsrep_drupal_282555_workaround=0
++
++# enable "strictly synchronous" semantics for read operations
++wsrep_causal_reads=0
++
++# Command to call when node status or cluster membership changes.
++# Will be passed all or some of the following options:
++# --status  - new status of this node
++# --uuid    - UUID of the cluster
++# --primary - whether the component is primary or not ("yes"/"no")
++# --members - comma-separated list of members
++# --index   - index of this node in the list
++wsrep_notify_cmd=
++
++##
++## WSREP State Transfer options
++##
++
++# State Snapshot Transfer method
++wsrep_sst_method=rsync
++
++# Address which donor should send State Snapshot to.
++# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!!
++# (SST method dependent. Defaults to the first IP of the first interface)
++#wsrep_sst_receive_address=
++
++# SST authentication string. This will be used to send SST to joining nodes.
++# Depends on SST method. For mysqldump method it is root:<root password>
++wsrep_sst_auth=root:
++
++# Desired SST donor name.
++#wsrep_sst_donor=
++
++# Reject client queries when donating SST (false)
++#wsrep_sst_donor_rejects_queries=0
++
++# Protocol version to use
++# wsrep_protocol_version=
+diff --git a/support-files/wsrep.cnf.sh b/support-files/wsrep.cnf.sh
+new file mode 100644
+index 0000000..756d4f6
+--- /dev/null
++++ b/support-files/wsrep.cnf.sh
+@@ -0,0 +1,129 @@
++# This file contains wsrep-related mysqld options. It should be included
++# in the main MySQL configuration file.
++#
++# Options that need to be customized:
++#  - wsrep_provider
++#  - wsrep_cluster_address
++#  - wsrep_sst_auth
++# The rest of defaults should work out of the box.
++
++##
++## mysqld options _MANDATORY_ for correct opration of the cluster
++##
++[mysqld]
++
++# (This must be substituted by wsrep_format)
++binlog_format=ROW
++
++# Currently only InnoDB storage engine is supported
++default-storage-engine=innodb
++
++# to avoid issues with 'bulk mode inserts' using autoinc
++innodb_autoinc_lock_mode=2
++
++# This is a must for paralell applying
++innodb_locks_unsafe_for_binlog=1
++
++# Query Cache is not supported with wsrep
++query_cache_size=0
++query_cache_type=0
++
++# Override bind-address
++# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST
++# it will have (most likely) disastrous consequences on donor node
++bind-address=0.0.0.0
++
++##
++## WSREP options
++##
++
++# Full path to wsrep provider library or 'none'
++wsrep_provider=none
++
++# Provider specific configuration options
++#wsrep_provider_options=
++
++# Logical cluster name. Should be the same for all nodes.
++wsrep_cluster_name="my_wsrep_cluster"
++
++# Group communication system handle
++#wsrep_cluster_address="dummy://"
++
++# Human-readable node name (non-unique). Hostname by default.
++#wsrep_node_name=
++
++# Base replication <address|hostname>[:port] of the node.
++# The values supplied will be used as defaults for state transfer receiving,
++# listening ports and so on. Default: address of the first network interface.
++#wsrep_node_address=
++
++# Address for incoming client connections. Autodetect by default.
++#wsrep_node_incoming_address=
++
++# How many threads will process writesets from other nodes
++wsrep_slave_threads=1
++
++# DBUG options for wsrep provider
++#wsrep_dbug_option
++
++# Generate fake primary keys for non-PK tables (required for multi-master
++# and parallel applying operation)
++wsrep_certify_nonPK=1
++
++# Maximum number of rows in write set
++wsrep_max_ws_rows=131072
++
++# Maximum size of write set
++wsrep_max_ws_size=1073741824
++
++# to enable debug level logging, set this to 1
++wsrep_debug=0
++
++# convert locking sessions into transactions
++wsrep_convert_LOCK_to_trx=0
++
++# how many times to retry deadlocked autocommits
++wsrep_retry_autocommit=1
++
++# change auto_increment_increment and auto_increment_offset automatically
++wsrep_auto_increment_control=1
++
++# retry autoinc insert, which failed for duplicate key error
++wsrep_drupal_282555_workaround=0
++
++# enable "strictly synchronous" semantics for read operations
++wsrep_causal_reads=0
++
++# Command to call when node status or cluster membership changes.
++# Will be passed all or some of the following options:
++# --status  - new status of this node
++# --uuid    - UUID of the cluster
++# --primary - whether the component is primary or not ("yes"/"no")
++# --members - comma-separated list of members
++# --index   - index of this node in the list
++wsrep_notify_cmd=
++
++##
++## WSREP State Transfer options
++##
++
++# State Snapshot Transfer method
++wsrep_sst_method=rsync
++
++# Address which donor should send State Snapshot to.
++# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!!
++# (SST method dependent. Defaults to the first IP of the first interface)
++#wsrep_sst_receive_address=
++
++# SST authentication string. This will be used to send SST to joining nodes.
++# Depends on SST method. For mysqldump method it is root:<root password>
++wsrep_sst_auth=root:
++
++# Desired SST donor name.
++#wsrep_sst_donor=
++
++# Reject client queries when donating SST (false)
++#wsrep_sst_donor_rejects_queries=0
++
++# Protocol version to use
++# wsrep_protocol_version=
+diff --git a/support-files/wsrep_notify.sh b/support-files/wsrep_notify.sh
+new file mode 100644
+index 0000000..bdbe3d1
+--- /dev/null
++++ b/support-files/wsrep_notify.sh
+@@ -0,0 +1,102 @@
++#!/bin/sh -eu
++
++# This is a simple example of wsrep notification script (wsrep_notify_cmd).
++# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status'
++# and fill them on every membership or node status change.
++#
++# Edit parameters below to specify the address and login to server.
++
++USER=root
++PSWD=rootpass
++HOST=127.0.0.1
++PORT=3306
++
++SCHEMA="wsrep"
++MEMB_TABLE="$SCHEMA.membership"
++STATUS_TABLE="$SCHEMA.status"
++
++BEGIN="
++SET wsrep_on=0;
++DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA;
++CREATE TABLE $MEMB_TABLE (
++    idx  INT UNIQUE PRIMARY KEY,
++    uuid CHAR(40) UNIQUE, /* node UUID */
++    name VARCHAR(32),     /* node name */
++    addr VARCHAR(256)     /* node address */
++) ENGINE=MEMORY;
++CREATE TABLE $STATUS_TABLE (
++    size   INT,      /* component size   */
++    idx    INT,      /* this node index  */
++    status CHAR(16), /* this node status */
++    uuid   CHAR(40), /* cluster UUID */
++    prim   BOOLEAN   /* if component is primary */
++) ENGINE=MEMORY;
++BEGIN;
++DELETE FROM $MEMB_TABLE;
++DELETE FROM $STATUS_TABLE;
++"
++END="COMMIT;"
++
++configuration_change()
++{
++    echo "$BEGIN;"
++
++    local idx=0
++
++    for NODE in $(echo $MEMBERS | sed s/,/\ /g)
++    do
++        echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, "
++        # Don't forget to properly quote string values
++        echo "'$NODE'" | sed  s/\\//\',\'/g
++        echo ");"
++        idx=$(( $idx + 1 ))
++    done
++
++    echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);"
++
++    echo "$END"
++}
++
++status_update()
++{
++    echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;"
++}
++
++COM=status_update # not a configuration change by default
++
++while [ $# -gt 0 ]
++do
++    case $1 in
++    --status)
++        STATUS=$2
++        shift
++        ;;
++    --uuid)
++        CLUSTER_UUID=$2
++        shift
++        ;;
++    --primary)
++        [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0"
++        COM=configuration_change
++        shift
++        ;;
++    --index)
++        INDEX=$2
++        shift
++        ;;
++    --members)
++        MEMBERS=$2
++        shift
++        ;;
++    esac
++    shift
++done
++
++# Undefined means node is shutting down
++if [ "$STATUS" != "Undefined" ]
++then
++    $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT
++fi
++
++exit 0
++#
+diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c
+index 4d5ff71..07e05e4 100644
+--- a/vio/viosslfactories.c
++++ b/vio/viosslfactories.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
++/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt
+new file mode 100644
+index 0000000..182e458
+--- /dev/null
++++ b/wsrep/CMakeLists.txt
+@@ -0,0 +1,24 @@
++# Copyright (c) 2012, Codership Oy. All rights reserved.
++# 
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++# 
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++# 
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
++
++INCLUDE_DIRECTORIES( "." )
++
++SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c)
++
++ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES})
++DTRACE_INSTRUMENT(wsrep)
++
++#ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES})
++#TARGET_LINK_LIBRARIES(listener ${LIBDL})
+diff --git a/wsrep/Makefile.am b/wsrep/Makefile.am
+new file mode 100644
+index 0000000..a748ece
+--- /dev/null
++++ b/wsrep/Makefile.am
+@@ -0,0 +1,7 @@
++noinst_LIBRARIES = libwsrep.a
++libwsrep_a_SOURCES = wsrep_api.h wsrep_loader.c wsrep_dummy.c wsrep_uuid.c wsrep_gtid.c
++noinst_PROGRAMS = wsrep_listener
++wsrep_listener_SOURCES = wsrep_listener.c
++wsrep_listener_LDADD = $(noinst_LIBRARIES)
++wsrep_listener_LDFLAGS = -static -ldl
++
+diff --git a/wsrep/wsrep_api.h b/wsrep/wsrep_api.h
+new file mode 100644
+index 0000000..c3304d7
+--- /dev/null
++++ b/wsrep/wsrep_api.h
+@@ -0,0 +1,1118 @@
++/* Copyright (C) 2009-2013 Codership Oy <info@codership.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with this program; if not, write to the Free Software Foundation, Inc.,
++   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++/*!
++  @file wsrep API declaration.
++
++  HOW TO READ THIS FILE.
++
++  Due to C language rules this header layout doesn't lend itself to intuitive
++  reading. So here's the scoop: in the end this header declares two main types:
++
++  * struct wsrep_init_args
++
++  and
++
++  * struct wsrep
++
++  wsrep_init_args contains initialization parameters for wsrep provider like
++  names, addresses, etc. and pointers to callbacks. The callbacks will be called
++  by provider when it needs to do something application-specific, like log a
++  message or apply a writeset. It should be passed to init() call from
++  wsrep API. It is an application part of wsrep API contract.
++
++  struct wsrep is the interface to wsrep provider. It contains all wsrep API
++  calls. It is a provider part of wsrep API contract.
++
++  Finally, wsrep_load() method loads (dlopens) wsrep provider library. It is
++  defined in wsrep_loader.c unit and is part of libwsrep.a (which is not a
++  wsrep provider, but a convenience library).
++
++  wsrep_unload() does the reverse.
++
++*/
++#ifndef WSREP_H
++#define WSREP_H
++
++#include <stdint.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <time.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**************************************************************************
++ *                                                                        *
++ *                       wsrep replication API                            *
++ *                                                                        *
++ **************************************************************************/
++
++#define WSREP_INTERFACE_VERSION "25"
++
++/*! Empty backend spec */
++#define WSREP_NONE "none"
++
++
++/*!
++ * @brief log severity levels, passed as first argument to log handler
++ */
++typedef enum wsrep_log_level
++{
++    WSREP_LOG_FATAL, //!< Unrecoverable error, application must quit.
++    WSREP_LOG_ERROR, //!< Operation failed, must be repeated.
++    WSREP_LOG_WARN,  //!< Unexpected condition, but no operational failure.
++    WSREP_LOG_INFO,  //!< Informational message.
++    WSREP_LOG_DEBUG  //!< Debug message. Shows only of compiled with debug.
++} wsrep_log_level_t;
++
++/*!
++ * @brief error log handler
++ *
++ *        All messages from wsrep provider are directed to this
++ *        handler, if present.
++ *
++ * @param level   log level
++ * @param message log message
++ */
++typedef void (*wsrep_log_cb_t)(wsrep_log_level_t, const char *);
++
++
++/*!
++ *  Certain provider capabilities application may want to know about
++ */
++#define WSREP_CAP_MULTI_MASTER          ( 1ULL << 0 )
++#define WSREP_CAP_CERTIFICATION         ( 1ULL << 1 )
++#define WSREP_CAP_PARALLEL_APPLYING     ( 1ULL << 2 )
++#define WSREP_CAP_TRX_REPLAY            ( 1ULL << 3 )
++#define WSREP_CAP_ISOLATION             ( 1ULL << 4 )
++#define WSREP_CAP_PAUSE                 ( 1ULL << 5 )
++#define WSREP_CAP_CAUSAL_READS          ( 1ULL << 6 )
++#define WSREP_CAP_CAUSAL_TRX            ( 1ULL << 7 )
++#define WSREP_CAP_INCREMENTAL_WRITESET  ( 1ULL << 8 )
++#define WSREP_CAP_SESSION_LOCKS         ( 1ULL << 9 )
++#define WSREP_CAP_DISTRIBUTED_LOCKS     ( 1ULL << 10 )
++#define WSREP_CAP_CONSISTENCY_CHECK     ( 1ULL << 11 )
++#define WSREP_CAP_UNORDERED             ( 1ULL << 12 )
++#define WSREP_CAP_ANNOTATION            ( 1ULL << 13 )
++#define WSREP_CAP_PREORDERED            ( 1ULL << 14 )
++
++
++/*!
++ *  Writeset flags
++ *
++ * COMMIT       the writeset and all preceding writesets must be committed
++ * ROLLBACK     all preceding writesets in a transaction must be rolled back
++ * ISOLATION    the writeset must be applied AND committed in isolation
++ * PA_UNSAFE    the writeset cannot be applied in parallel
++ * COMMUTATIVE  the order in which the writeset is applied does not matter
++ * NATIVE       the writeset contains another writeset in this provider format
++ *
++ * Note that some of the flags are mutually exclusive (e.g. COMMIT and
++ * ROLLBACK).
++ */
++#define WSREP_FLAG_COMMIT               ( 1ULL << 0 )
++#define WSREP_FLAG_ROLLBACK             ( 1ULL << 1 )
++#define WSREP_FLAG_ISOLATION            ( 1ULL << 2 )
++#define WSREP_FLAG_PA_UNSAFE            ( 1ULL << 3 )
++#define WSREP_FLAG_COMMUTATIVE          ( 1ULL << 4 )
++#define WSREP_FLAG_NATIVE               ( 1ULL << 5 )
++
++
++typedef uint64_t wsrep_trx_id_t;  //!< application transaction ID
++typedef uint64_t wsrep_conn_id_t; //!< application connection ID
++typedef int64_t  wsrep_seqno_t;   //!< sequence number of a writeset, etc.
++#ifdef __cplusplus
++typedef bool     wsrep_bool_t;
++#else
++typedef _Bool    wsrep_bool_t;    //!< should be the same as standard (C99) bool
++#endif /* __cplusplus */
++
++/*! undefined seqno */
++#define WSREP_SEQNO_UNDEFINED (-1)
++
++
++/*! wsrep provider status codes */
++typedef enum wsrep_status
++{
++    WSREP_OK = 0,          //!< success
++    WSREP_WARNING,         //!< minor warning, error logged
++    WSREP_TRX_MISSING,     //!< transaction is not known by wsrep
++    WSREP_TRX_FAIL,        //!< transaction aborted, server can continue
++    WSREP_BF_ABORT,        //!< trx was victim of brute force abort
++    WSREP_SIZE_EXCEEDED,   //!< data exceeded maximum supported size
++    WSREP_CONN_FAIL,       //!< error in client connection, must abort
++    WSREP_NODE_FAIL,       //!< error in node state, wsrep must reinit
++    WSREP_FATAL,           //!< fatal error, server must abort
++    WSREP_NOT_IMPLEMENTED  //!< feature not implemented
++} wsrep_status_t;
++
++
++/*! wsrep callbacks status codes */
++typedef enum wsrep_cb_status
++{
++    WSREP_CB_SUCCESS =  0, //!< success (as in "not critical failure")
++    WSREP_CB_FAILURE       //!< critical failure (consistency violation)
++    /* Technically, wsrep provider has no use for specific failure codes since
++     * there is nothing it can do about it but abort execution. Therefore any
++     * positive number shall indicate a critical failure. Optionally that value
++     * may be used by provider to come to a consensus about state consistency
++     * in a group of nodes. */
++} wsrep_cb_status_t;
++
++
++/*!
++ * UUID type - for all unique IDs
++ */
++typedef struct wsrep_uuid {
++    uint8_t data[16];
++} wsrep_uuid_t;
++
++/*! Undefined UUID */
++static const wsrep_uuid_t WSREP_UUID_UNDEFINED = {{0,}};
++
++/*! UUID string representation length, terminating '\0' not included */
++#define WSREP_UUID_STR_LEN 36
++
++/*!
++ * Scan UUID from string
++ * @return length of UUID string representation or negative error code
++ */
++extern int
++wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid);
++
++/*!
++ * Print UUID to string
++ * @return length of UUID string representation or negative error code
++ */
++extern int
++wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len);
++
++#define WSREP_MEMBER_NAME_LEN 32  //!< maximum logical member name length
++#define WSREP_INCOMING_LEN    256 //!< max Domain Name length + 0x00
++
++
++/*!
++ * Global transaction identifier
++ */
++typedef struct wsrep_gtid
++{
++    wsrep_uuid_t  uuid;  /*!< History UUID */
++    wsrep_seqno_t seqno; /*!< Sequence number */
++} wsrep_gtid_t;
++
++/*! Undefined GTID */
++static const wsrep_gtid_t WSREP_GTID_UNDEFINED = {{{0, }}, -1};
++
++/*! Minimum number of bytes guaranteed to store GTID string representation,
++ * terminating '\0' not included (36 + 1 + 20) */
++#define WSREP_GTID_STR_LEN 57
++
++
++/*!
++ * Scan GTID from string
++ * @return length of GTID string representation or negative error code
++ */
++extern int
++wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid);
++
++/*!
++ * Print GTID to string
++ * @return length of GTID string representation or negative error code
++ */
++extern int
++wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len);
++
++
++/*!
++ * Transaction meta data
++ */
++typedef struct wsrep_trx_meta
++{
++    wsrep_gtid_t  gtid;       /*!< Global transaction identifier */
++    wsrep_seqno_t depends_on; /*!< Sequence number part of the last transaction
++                                   this transaction depends on */
++} wsrep_trx_meta_t;
++
++
++/*!
++ * member status
++ */
++typedef enum wsrep_member_status {
++    WSREP_MEMBER_UNDEFINED, //!< undefined state
++    WSREP_MEMBER_JOINER,    //!< incomplete state, requested state transfer
++    WSREP_MEMBER_DONOR,     //!< complete state, donates state transfer
++    WSREP_MEMBER_JOINED,    //!< complete state
++    WSREP_MEMBER_SYNCED,    //!< complete state, synchronized with group
++    WSREP_MEMBER_ERROR,     //!< this and above is provider-specific error code
++    WSREP_MEMBER_MAX
++} wsrep_member_status_t;
++
++/*!
++ * static information about a group member (some fields are tentative yet)
++ */
++typedef struct wsrep_member_info {
++    wsrep_uuid_t id;                           //!< group-wide unique member ID
++    char         name[WSREP_MEMBER_NAME_LEN];  //!< human-readable name
++    char         incoming[WSREP_INCOMING_LEN]; //!< address for client requests
++} wsrep_member_info_t;
++
++/*!
++ * group status
++ */
++typedef enum wsrep_view_status {
++    WSREP_VIEW_PRIMARY,      //!< primary group configuration (quorum present)
++    WSREP_VIEW_NON_PRIMARY,  //!< non-primary group configuration (quorum lost)
++    WSREP_VIEW_DISCONNECTED, //!< not connected to group, retrying.
++    WSREP_VIEW_MAX
++} wsrep_view_status_t;
++
++/*!
++ * view of the group
++ */
++typedef struct wsrep_view_info {
++    wsrep_gtid_t        state_id;  //!< global state ID
++    wsrep_seqno_t       view;      //!< global view number
++    wsrep_view_status_t status;    //!< view status
++    wsrep_bool_t        state_gap; //!< gap between global and local states
++    int                 my_idx;    //!< index of this member in the view
++    int                 memb_num;  //!< number of members in the view
++    int                 proto_ver; //!< application protocol agreed on the view
++    wsrep_member_info_t members[1];//!< array of member information
++} wsrep_view_info_t;
++
++/*!
++ * Magic string to tell provider to engage into trivial (empty) state transfer.
++ * No data will be passed, but the node shall be considered JOINED.
++ * Should be passed in sst_req parameter of wsrep_view_cb_t.
++ */
++#define WSREP_STATE_TRANSFER_TRIVIAL "trivial"
++
++/*!
++ * Magic string to tell provider not to engage in state transfer at all.
++ * The member will stay in WSREP_MEMBER_UNDEFINED state but will keep on
++ * receiving all writesets.
++ * Should be passed in sst_req parameter of wsrep_view_cb_t.
++ */
++#define WSREP_STATE_TRANSFER_NONE "none"
++
++/*!
++ * @brief group view handler
++ *
++ * This handler is called in total order corresponding to the group
++ * configuration change. It is to provide a vital information about
++ * new group view. If view info indicates existence of discontinuity
++ * between group and member states, state transfer request message
++ * should be filled in by the callback implementation.
++ *
++ * @note Currently it is assumed that sst_req is allocated using
++ *       malloc()/calloc()/realloc() and it will be freed by
++ *       wsrep implementation.
++ *
++ * @param app_ctx     application context
++ * @param recv_ctx    receiver context
++ * @param view        new view on the group
++ * @param state       current state
++ * @param state_len   lenght of current state
++ * @param sst_req     location to store SST request
++ * @param sst_req_len location to store SST request length or error code,
++ *                    value of 0 means no SST.
++ */
++typedef enum wsrep_cb_status (*wsrep_view_cb_t) (
++    void*                    app_ctx,
++    void*                    recv_ctx,
++    const wsrep_view_info_t* view,
++    const char*              state,
++    size_t                   state_len,
++    void**                   sst_req,
++    size_t*                  sst_req_len
++);
++
++
++/*!
++ * @brief apply callback
++ *
++ * This handler is called from wsrep library to apply replicated writeset
++ * Must support brute force applying for multi-master operation
++ *
++ * @param recv_ctx receiver context pointer provided by the application
++ * @param data     data buffer containing the writeset
++ * @param size     data buffer size
++ * @param flags    WSREP_FLAG_... flags
++ * @param meta     transaction meta data of the writeset to be applied
++ *
++ * @return success code:
++ * @retval WSREP_OK
++ * @retval WSREP_NOT_IMPLEMENTED appl. does not support the writeset format
++ * @retval WSREP_ERROR failed to apply the writeset
++ */
++typedef enum wsrep_cb_status (*wsrep_apply_cb_t) (
++    void*                   recv_ctx,
++    const void*             data,
++    size_t                  size,
++    uint32_t                flags,
++    const wsrep_trx_meta_t* meta
++);
++
++
++/*!
++ * @brief commit callback
++ *
++ * This handler is called to commit the changes made by apply callback.
++ *
++ * @param recv_ctx receiver context pointer provided by the application
++ * @param flags    WSREP_FLAG_... flags
++ * @param meta     transaction meta data of the writeset to be committed
++ * @param exit     set to true to exit recv loop
++ * @param commit   true - commit writeset, false - rollback writeset
++ *
++ * @return success code:
++ * @retval WSREP_OK
++ * @retval WSREP_ERROR call failed
++ */
++typedef enum wsrep_cb_status (*wsrep_commit_cb_t) (
++    void*                   recv_ctx,
++    uint32_t                flags,
++    const wsrep_trx_meta_t* meta,
++    wsrep_bool_t*           exit,
++    wsrep_bool_t            commit
++);
++
++
++/*!
++ * @brief unordered callback
++ *
++ * This handler is called to execute unordered actions (actions that need not
++ * to be executed in any particular order) attached to writeset.
++ *
++ * @param recv_ctx receiver context pointer provided by the application
++ * @param data     data buffer containing the writeset
++ * @param size     data buffer size
++ */
++typedef enum wsrep_cb_status (*wsrep_unordered_cb_t) (
++    void*       recv_ctx,
++    const void* data,
++    size_t      size
++);
++
++
++/*!
++ * @brief a callback to donate state snapshot
++ *
++ * This handler is called from wsrep library when it needs this node
++ * to deliver state to a new cluster member.
++ * No state changes will be committed for the duration of this call.
++ * Wsrep implementation may provide internal state to be transmitted
++ * to new cluster member for initial state.
++ *
++ * @param app_ctx   application context
++ * @param recv_ctx  receiver context
++ * @param msg       state transfer request message
++ * @param msg_len   state transfer request message length
++ * @param gtid      current state ID on this node
++ * @param state     current wsrep internal state buffer
++ * @param state_len current wsrep internal state buffer len
++ * @param bypass    bypass snapshot transfer, only transfer uuid:seqno pair
++ */
++typedef enum wsrep_cb_status (*wsrep_sst_donate_cb_t) (
++    void*               app_ctx,
++    void*               recv_ctx,
++    const void*         msg,
++    size_t              msg_len,
++    const wsrep_gtid_t* state_id,
++    const char*         state,
++    size_t              state_len,
++    wsrep_bool_t        bypass
++);
++
++
++/*!
++ * @brief a callback to signal application that wsrep state is synced
++ *        with cluster
++ *
++ * This callback is called after wsrep library has got in sync with
++ * rest of the cluster.
++ *
++ * @param app_ctx application context
++ */
++typedef void (*wsrep_synced_cb_t) (void* app_ctx);
++
++
++/*!
++ * Initialization parameters for wsrep provider.
++ */
++struct wsrep_init_args
++{
++    void* app_ctx;             //!< Application context for callbacks
++
++    /* Configuration parameters */
++    const char* node_name;     //!< Symbolic name of this node (e.g. hostname)
++    const char* node_address;  //!< Address to be used by wsrep provider
++    const char* node_incoming; //!< Address for incoming client connections
++    const char* data_dir;      //!< Directory where wsrep files are kept if any
++    const char* options;       //!< Provider-specific configuration string
++    int         proto_ver;     //!< Max supported application protocol version
++
++    /* Application initial state information. */
++    const wsrep_gtid_t* state_id;    //!< Application state GTID
++    const char*         state;       //!< Initial state for wsrep provider
++    size_t              state_len;   //!< Length of state buffer
++
++    /* Application callbacks */
++    wsrep_log_cb_t        logger_cb;       //!< logging handler
++    wsrep_view_cb_t       view_handler_cb; //!< group view change handler
++
++    /* Applier callbacks */
++    wsrep_apply_cb_t      apply_cb;        //!< apply  callback
++    wsrep_commit_cb_t     commit_cb;       //!< commit callback
++    wsrep_unordered_cb_t  unordered_cb;    //!< callback for unordered actions
++
++    /* State Snapshot Transfer callbacks */
++    wsrep_sst_donate_cb_t sst_donate_cb;   //!< starting to donate
++    wsrep_synced_cb_t     synced_cb;       //!< synced with group
++};
++
++
++/*! Type of the stats variable value in struct wsrep_status_var */
++typedef enum wsrep_var_type
++{
++    WSREP_VAR_STRING, //!< pointer to null-terminated string
++    WSREP_VAR_INT64,  //!< int64_t
++    WSREP_VAR_DOUBLE  //!< double
++}
++wsrep_var_type_t;
++
++/*! Generalized stats variable representation */
++struct wsrep_stats_var
++{
++    const char*      name;     //!< variable name
++    wsrep_var_type_t type;     //!< variable value type
++    union {
++        int64_t     _int64;
++        double      _double;
++        const char* _string;
++    } value;                   //!< variable value
++};
++
++
++/*! Abstract data buffer structure */
++typedef struct wsrep_buf
++{
++    const void* ptr; /*!< Pointer to data buffer */
++    size_t      len; /*!< Length of buffer */
++} wsrep_buf_t;
++
++/*! Key struct used to pass certification keys for transaction handling calls.
++ *  A key consists of zero or more key parts. */
++typedef struct wsrep_key
++{
++    const wsrep_buf_t* key_parts;     /*!< Array of key parts  */
++    size_t             key_parts_num; /*!< Number of key parts */
++} wsrep_key_t;
++
++/*! Key type:
++ *  EXCLUSIVE conflicts with any key type
++ *  SEMI      reserved. If not supported, should be interpeted as EXCLUSIVE
++ *  SHARED    conflicts only with EXCLUSIVE keys */
++typedef enum wsrep_key_type
++{
++    WSREP_KEY_SHARED = 0,
++    WSREP_KEY_SEMI,
++    WSREP_KEY_EXCLUSIVE
++} wsrep_key_type_t;
++
++/*! Data type:
++ *  ORDERED    state modification event that should be applied and committed
++ *             in order.
++ *  UNORDERED  some action that does not modify state and execution of which is
++ *             optional and does not need to happen in order.
++ *  ANNOTATION (human readable) writeset annotation. */
++typedef enum wsrep_data_type
++{
++    WSREP_DATA_ORDERED = 0,
++    WSREP_DATA_UNORDERED,
++    WSREP_DATA_ANNOTATION
++} wsrep_data_type_t;
++
++
++/*! Transaction handle struct passed for wsrep transaction handling calls */
++typedef struct wsrep_ws_handle
++{
++    wsrep_trx_id_t trx_id; //!< transaction ID
++    void*          opaque; //!< opaque provider transaction context data
++} wsrep_ws_handle_t;
++
++/*!
++ * @brief Helper method to reset trx writeset handle state when trx id changes
++ *
++ * Instead of passing wsrep_ws_handle_t directly to wsrep calls,
++ * wrapping handle with this call offloads bookkeeping from
++ * application.
++ */
++static inline wsrep_ws_handle_t* wsrep_ws_handle_for_trx(
++    wsrep_ws_handle_t* ws_handle,
++    wsrep_trx_id_t     trx_id)
++{
++    if (ws_handle->trx_id != trx_id)
++    {
++        ws_handle->trx_id = trx_id;
++        ws_handle->opaque = NULL;
++    }
++    return ws_handle;
++}
++
++
++/*!
++ *  A handle for processing preordered actions.
++ *  Must be initialized to WSREP_PO_INITIALIZER before use.
++ */
++typedef struct wsrep_po_handle { void* opaque; } wsrep_po_handle_t;
++
++static const wsrep_po_handle_t WSREP_PO_INITIALIZER = { NULL };
++
++
++typedef struct wsrep wsrep_t;
++/*!
++ * wsrep interface for dynamically loadable libraries
++ */
++struct wsrep {
++
++    const char *version; //!< interface version string
++
++  /*!
++   * @brief Initializes wsrep provider
++   *
++   * @param wsrep provider handle
++   * @param args  wsrep initialization parameters
++   */
++    wsrep_status_t (*init)   (wsrep_t*                      wsrep,
++                              const struct wsrep_init_args* args);
++
++  /*!
++   * @brief Returns provider capabilities flag bitmap
++   *
++   * @param wsrep provider handle
++   */
++    uint64_t (*capabilities) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Passes provider-specific configuration string to provider.
++   *
++   * @param wsrep provider handle
++   * @param conf  configuration string
++   *
++   * @retval WSREP_OK      configuration string was parsed successfully
++   * @retval WSREP_WARNING could't not parse conf string, no action taken
++   */
++    wsrep_status_t (*options_set) (wsrep_t* wsrep, const char* conf);
++
++  /*!
++   * @brief Returns provider-specific string with current configuration values.
++   *
++   * @param wsrep provider handle
++   *
++   * @return a dynamically allocated string with current configuration
++   *         parameter values
++   */
++    char*          (*options_get) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Opens connection to cluster
++   *
++   * Returns when either node is ready to operate as a part of the clsuter
++   * or fails to reach operating status.
++   *
++   * @param wsrep        provider handle
++   * @param cluster_name unique symbolic cluster name
++   * @param cluster_url  URL-like cluster address (backend://address)
++   * @param state_donor  name of the node to be asked for state transfer.
++   * @param bootstrap    a flag to request initialization of a new wsrep
++   *                     service rather then a connection to the existing one.
++   *                     clister_url may still carry important initialization
++   *                     parameters, like backend spec and/or listen address.
++   */
++    wsrep_status_t (*connect) (wsrep_t*     wsrep,
++                               const char*  cluster_name,
++                               const char*  cluster_url,
++                               const char*  state_donor,
++                               wsrep_bool_t bootstrap);
++
++  /*!
++   * @brief Closes connection to cluster.
++   *
++   * If state_uuid and/or state_seqno is not NULL, will store final state
++   * in there.
++   *
++   * @param wsrep this  wsrep handler
++   */
++    wsrep_status_t (*disconnect)(wsrep_t* wsrep);
++
++  /*!
++   * @brief start receiving replication events
++   *
++   * This function never returns
++   *
++   * @param wsrep provider handle
++   * @param recv_ctx receiver context
++   */
++    wsrep_status_t (*recv)(wsrep_t* wsrep, void* recv_ctx);
++
++  /*!
++   * @brief Replicates/logs result of transaction to other nodes and allocates
++   * required resources.
++   *
++   * Must be called before transaction commit. Returns success code, which
++   * caller must check.
++   * In case of WSREP_OK, starts commit critical section, transaction can
++   * commit. Otherwise transaction must rollback.
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset of committing transaction
++   * @param conn_id    connection ID
++   * @param flags      fine tuning the replication WSREP_FLAG_*
++   * @param meta       transaction meta data
++   *
++   * @retval WSREP_OK         cluster-wide commit succeeded
++   * @retval WSREP_TRX_FAIL   must rollback transaction
++   * @retval WSREP_CONN_FAIL  must close client connection
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*pre_commit)(wsrep_t*                wsrep,
++                                 wsrep_conn_id_t         conn_id,
++                                 wsrep_ws_handle_t*      ws_handle,
++                                 uint32_t                flags,
++                                 wsrep_trx_meta_t*       meta);
++
++  /*!
++   * @brief Releases resources after transaction commit.
++   *
++   * Ends commit critical section.
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset of committing transaction
++   * @retval WSREP_OK  post_commit succeeded
++   */
++    wsrep_status_t (*post_commit) (wsrep_t*            wsrep,
++                                   wsrep_ws_handle_t*  ws_handle);
++
++  /*!
++   * @brief Releases resources after transaction rollback.
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset of committing transaction
++   * @retval WSREP_OK  post_rollback succeeded
++   */
++    wsrep_status_t (*post_rollback)(wsrep_t*            wsrep,
++                                    wsrep_ws_handle_t*  ws_handle);
++
++  /*!
++   * @brief Replay trx as a slave writeset
++   *
++   * If local trx has been aborted by brute force, and it has already
++   * replicated before this abort, we must try if we can apply it as
++   * slave trx. Note that slave nodes see only trx writesets and certification
++   * test based on write set content can be different to DBMS lock conflicts.
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset of committing transaction
++   * @param trx_ctx    transaction context
++   *
++   * @retval WSREP_OK         cluster commit succeeded
++   * @retval WSREP_TRX_FAIL   must rollback transaction
++   * @retval WSREP_BF_ABORT   brute force abort happened after trx replicated
++   *                          must rollback transaction and try to replay
++   * @retval WSREP_CONN_FAIL  must close client connection
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*replay_trx)(wsrep_t*            wsrep,
++                                 wsrep_ws_handle_t*  ws_handle,
++                                 void*               trx_ctx);
++
++  /*!
++   * @brief Abort pre_commit() call of another thread.
++   *
++   * It is possible, that some high-priority transaction needs to abort
++   * another transaction which is in pre_commit() call waiting for resources.
++   *
++   * The kill routine checks that abort is not attmpted against a transaction
++   * which is front of the caller (in total order).
++   *
++   * @param wsrep      provider handle
++   * @param bf_seqno   seqno of brute force trx, running this cancel
++   * @param victim_trx transaction to be aborted, and which is committing
++   *
++   * @retval WSREP_OK       abort secceded
++   * @retval WSREP_WARNING  abort failed
++   */
++    wsrep_status_t (*abort_pre_commit)(wsrep_t*       wsrep,
++                                       wsrep_seqno_t  bf_seqno,
++                                       wsrep_trx_id_t victim_trx);
++
++  /*!
++   * @brief Appends a row reference to transaction writeset
++   *
++   * Both copy flag and key_type can be ignored by provider (key type
++   * interpreted as WSREP_KEY_EXCLUSIVE).
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset handle
++   * @param keys       array of keys
++   * @param count      length of the array of keys
++   * @param type       type ot the key
++   * @param copy       can be set to FALSE if keys persist through commit.
++   */
++    wsrep_status_t (*append_key)(wsrep_t*            wsrep,
++                                 wsrep_ws_handle_t*  ws_handle,
++                                 const wsrep_key_t*  keys,
++                                 size_t              count,
++                                 enum wsrep_key_type type,
++                                 wsrep_bool_t        copy);
++
++  /*!
++   * @brief Appends data to transaction writeset
++   *
++   * This method can be called any time before commit and it
++   * appends a number of data buffers to transaction writeset.
++   *
++   * Both copy and unordered flags can be ignored by provider.
++   *
++   * @param wsrep      provider handle
++   * @param ws_handle  writeset handle
++   * @param data       array of data buffers
++   * @param count      buffer count
++   * @param type       type of data
++   * @param copy       can be set to FALSE if data persists through commit.
++   */
++    wsrep_status_t (*append_data)(wsrep_t*                wsrep,
++                                  wsrep_ws_handle_t*      ws_handle,
++                                  const struct wsrep_buf* data,
++                                  size_t                  count,
++                                  enum wsrep_data_type    type,
++                                  wsrep_bool_t            copy);
++
++  /*!
++   * @brief Get causal ordering for read operation
++   *
++   * This call will block until causal ordering with all possible
++   * preceding writes in the cluster is guaranteed. If pointer to
++   * gtid is non-null, the call stores the global transaction ID
++   * of the last transaction which is guaranteed to be ordered
++   * causally before this call.
++   *
++   * @param wsrep provider handle
++   * @param gtid  location to store GTID
++   */
++    wsrep_status_t (*causal_read)(wsrep_t* wsrep, wsrep_gtid_t* gtid);
++
++  /*!
++   * @brief Clears allocated connection context.
++   *
++   * Whenever a new connection ID is passed to wsrep provider through
++   * any of the API calls, a connection context is allocated for this
++   * connection. This call is to explicitly notify provider fo connection
++   * closing.
++   *
++   * @param wsrep       provider handle
++   * @param conn_id     connection ID
++   * @param query       the 'set database' query
++   * @param query_len   length of query (does not end with 0)
++   */
++    wsrep_status_t (*free_connection)(wsrep_t*        wsrep,
++                                      wsrep_conn_id_t conn_id);
++
++  /*!
++   * @brief Replicates a query and starts "total order isolation" section.
++   *
++   * Replicates the action spec and returns success code, which caller must
++   * check. Total order isolation continues until to_execute_end() is called.
++   *
++   * @param wsrep       provider handle
++   * @param conn_id     connection ID
++   * @param keys        array of keys
++   * @param keys_num    lenght of the array of keys
++   * @param action      action buffer array to be executed
++   * @param count       action buffer count
++   * @param meta        transaction meta data
++   *
++   * @retval WSREP_OK         cluster commit succeeded
++   * @retval WSREP_CONN_FAIL  must close client connection
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*to_execute_start)(wsrep_t*                wsrep,
++                                       wsrep_conn_id_t         conn_id,
++                                       const wsrep_key_t*      keys,
++                                       size_t                  keys_num,
++                                       const struct wsrep_buf* action,
++                                       size_t                  count,
++                                       wsrep_trx_meta_t*       meta);
++
++  /*!
++   * @brief Ends the total order isolation section.
++   *
++   * Marks the end of total order isolation. TO locks are freed
++   * and other transactions are free to commit from this point on.
++   *
++   * @param wsrep provider handle
++   * @param conn_id connection ID
++   *
++   * @retval WSREP_OK         cluster commit succeeded
++   * @retval WSREP_CONN_FAIL  must close client connection
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*to_execute_end)(wsrep_t* wsrep, wsrep_conn_id_t conn_id);
++
++  /*!
++   * @brief Collects preordered replication events into a writeset.
++   *
++   * @param wsrep   wsrep provider handle
++   * @param handle  a handle associated with a given writeset
++   * @param data    an array of data buffers.
++   * @param count   length of data buffer array.
++   * @param copy    whether provider needs to make a copy of events.
++   *
++   * @retval WSREP_OK         cluster-wide commit succeeded
++   * @retval WSREP_TRX_FAIL   operation failed (e.g. trx size exceeded limit)
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*preordered_collect) (wsrep_t*                 wsrep,
++                                          wsrep_po_handle_t*       handle,
++                                          const struct wsrep_buf*  data,
++                                          size_t                   count,
++                                          wsrep_bool_t             copy);
++
++  /*!
++   * @brief "Commits" preordered writeset to cluster.
++   *
++   * The contract is that the writeset will be committed in the same (partial)
++   * order this method was called. Frees resources associated with the writeset
++   * handle and reinitializes the handle.
++   *
++   * @param wsrep     wsrep provider handle
++   * @param po_handle a handle associated with a given writeset
++   * @param source_id ID of the event producer, also serves as the partial order
++   *                  or stream ID - events with different source_ids won't be
++   *                  ordered with respect to each other.
++   * @param flags     WSREP_FLAG_... flags
++   * @param pa_range  the number of preceding events this event can be processed
++   *                  in parallel with. A value of 0 means strict serial
++   *                  processing. Note: commits always happen in wsrep order.
++   * @param commit    'true'  to commit writeset to cluster (replicate) or
++   *                  'false' to rollback (cancel) the writeset.
++   *
++   * @retval WSREP_OK         cluster-wide commit succeeded
++   * @retval WSREP_TRX_FAIL   operation failed (e.g. NON-PRIMARY component)
++   * @retval WSREP_NODE_FAIL  must close all connections and reinit
++   */
++    wsrep_status_t (*preordered_commit)  (wsrep_t*             wsrep,
++                                          wsrep_po_handle_t*   handle,
++                                          const wsrep_uuid_t*  source_id,
++                                          uint32_t             flags,
++                                          int                  pa_range,
++                                          wsrep_bool_t         commit);
++
++  /*!
++   * @brief Signals to wsrep provider that state snapshot has been sent to
++   *        joiner.
++   *
++   * @param wsrep    provider handle
++   * @param state_id state ID
++   * @param rcode    0 or negative error code of the operation.
++   */
++    wsrep_status_t (*sst_sent)(wsrep_t*            wsrep,
++                               const wsrep_gtid_t* state_id,
++                               int                 rcode);
++
++  /*!
++   * @brief Signals to wsrep provider that new state snapshot has been received.
++   *        May deadlock if called from sst_prepare_cb.
++   *
++   * @param wsrep     provider handle
++   * @param state_id  state ID
++   * @param state     initial state provided by SST donor
++   * @param state_len length of state buffer
++   * @param rcode     0 or negative error code of the operation.
++   */
++    wsrep_status_t (*sst_received)(wsrep_t*            wsrep,
++                                   const wsrep_gtid_t* state_id,
++                                   const void*         state,
++                                   size_t              state_len,
++                                   int                 rcode);
++
++
++  /*!
++   * @brief Generate request for consistent snapshot.
++   *
++   * If successfull, this call will generate internally SST request
++   * which in turn triggers calling SST donate callback on the nodes
++   * specified in donor_spec. If donor_spec is null, callback is
++   * called only locally. This call will block until sst_sent is called
++   * from callback.
++   *
++   * @param wsrep      provider handle
++   * @param msg        context message for SST donate callback
++   * @param msg_len    length of context message
++   * @param donor_spec list of snapshot donors
++   */
++    wsrep_status_t (*snapshot)(wsrep_t*    wsrep,
++                               const void* msg,
++                               size_t      msg_len,
++                               const char* donor_spec);
++
++  /*!
++   * @brief Returns an array fo status variables.
++   *        Array is terminated by Null variable name.
++   *
++   * @param wsrep provider handle
++   * @return array of struct wsrep_status_var.
++   */
++    struct wsrep_stats_var* (*stats_get) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Release resources that might be associated with the array.
++   *
++   * @param wsrep     provider handle.
++   * @param var_array array returned by stats_get().
++   */
++    void (*stats_free) (wsrep_t* wsrep, struct wsrep_stats_var* var_array);
++
++  /*!
++   * @brief Reset some stats variables to inital value, provider-dependent.
++   *
++   * @param wsrep provider handle.
++   */
++    void (*stats_reset) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Pauses writeset applying/committing.
++   *
++   * @return global sequence number of the paused state or negative error code.
++   */
++    wsrep_seqno_t (*pause) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Resumes writeset applying/committing.
++   */
++    wsrep_status_t (*resume) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Desynchronize from cluster
++   *
++   * Effectively turns off flow control for this node, allowing it
++   * to fall behind the cluster.
++   */
++    wsrep_status_t (*desync) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Request to resynchronize with cluster.
++   *
++   * Effectively turns on flow control. Asynchronous - actual synchronization
++   * event to be deliverred via sync_cb.
++   */
++    wsrep_status_t (*resync) (wsrep_t* wsrep);
++
++  /*!
++   * @brief Acquire global named lock
++   *
++   * @param wsrep  wsrep provider handle
++   * @param name   lock name
++   * @param shared shared or exclusive lock
++   * @param owner  64-bit owner ID
++   * @param tout   timeout in nanoseconds.
++   *               0 - return immediately, -1 wait forever.
++   * @return          wsrep status or negative error code
++   * @retval -EDEADLK lock was already acquired by this thread
++   * @retval -EBUSY   lock was busy
++   */
++    wsrep_status_t (*lock) (wsrep_t* wsrep,
++                            const char* name, wsrep_bool_t shared,
++                            uint64_t owner, int64_t tout);
++
++  /*!
++   * @brief Release global named lock
++   *
++   * @param wsrep   wsrep provider handle
++   * @param name    lock name
++   * @param owner   64-bit owner ID
++   * @return        wsrep status or negative error code
++   * @retval -EPERM lock does not belong to this owner
++   */
++    wsrep_status_t (*unlock) (wsrep_t* wsrep, const char* name, uint64_t owner);
++
++  /*!
++   * @brief Check if global named lock is locked
++   *
++   * @param wsrep wsrep provider handle
++   * @param name  lock name
++   * @param owner if not NULL will contain 64-bit owner ID
++   * @param node  if not NULL will contain owner's node UUID
++   * @return true if lock is locked
++   */
++    wsrep_bool_t (*is_locked) (wsrep_t* wsrep, const char* name, uint64_t* conn,
++                               wsrep_uuid_t* node);
++
++  /*!
++   * wsrep provider name
++   */
++    const char* provider_name;
++
++  /*!
++   * wsrep provider version
++   */
++    const char* provider_version;
++
++  /*!
++   * wsrep provider vendor name
++   */
++    const char* provider_vendor;
++
++  /*!
++   * @brief Frees allocated resources before unloading the library.
++   * @param wsrep provider handle
++   */
++    void (*free)(wsrep_t* wsrep);
++
++    void *dlh;    //!< reserved for future use
++    void *ctx;    //!< reserved for implemetation private context
++};
++
++
++/*!
++ *
++ * @brief Loads wsrep library
++ *
++ * @param spec   path to wsrep library. If NULL or WSREP_NONE initialises dummy
++ *               pass-through implementation.
++ * @param hptr   wsrep handle
++ * @param log_cb callback to handle loader messages. Otherwise writes to stderr.
++ *
++ * @return zero on success, errno on failure
++ */
++int wsrep_load(const char* spec, wsrep_t** hptr, wsrep_log_cb_t log_cb);
++
++/*!
++ * @brief Unloads wsrep library and frees associated resources
++ *
++ * @param hptr wsrep handler pointer
++ */
++void wsrep_unload(wsrep_t* hptr);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* WSREP_H */
+diff --git a/wsrep/wsrep_dummy.c b/wsrep/wsrep_dummy.c
+new file mode 100644
+index 0000000..bab5329
+--- /dev/null
++++ b/wsrep/wsrep_dummy.c
+@@ -0,0 +1,407 @@
++/* Copyright (C) 2009-2010 Codership Oy <info@codersihp.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*! @file Dummy wsrep API implementation. */
++
++#include "wsrep_api.h"
++
++#include <errno.h>
++#include <stdbool.h>
++#include <string.h>
++
++/*! Dummy backend context. */
++typedef struct wsrep_dummy
++{
++    wsrep_log_cb_t log_fn;
++    char* options;
++} wsrep_dummy_t;
++
++/* Get pointer to wsrep_dummy context from wsrep_t pointer */
++#define WSREP_DUMMY(_p) ((wsrep_dummy_t *) (_p)->ctx)
++
++/* Trace function usage a-la DBUG */
++#define WSREP_DBUG_ENTER(_w) do {                                       \
++        if (WSREP_DUMMY(_w)) {                                          \
++            if (WSREP_DUMMY(_w)->log_fn)                                \
++                WSREP_DUMMY(_w)->log_fn(WSREP_LOG_DEBUG, __FUNCTION__); \
++        }                                                               \
++    } while (0)
++
++
++static void dummy_free(wsrep_t *w)
++{
++    WSREP_DBUG_ENTER(w);
++    if (WSREP_DUMMY(w)->options) {
++        free(WSREP_DUMMY(w)->options);
++        WSREP_DUMMY(w)->options = NULL;
++    }
++    free(w->ctx);
++    w->ctx = NULL;
++}
++
++static wsrep_status_t dummy_init (wsrep_t* w,
++                                  const struct wsrep_init_args* args)
++{
++    WSREP_DUMMY(w)->log_fn = args->logger_cb;
++    WSREP_DBUG_ENTER(w);
++    if (args->options) {
++        WSREP_DUMMY(w)->options = strdup(args->options);
++    }
++    return WSREP_OK;
++}
++
++static uint64_t dummy_capabilities (wsrep_t* w __attribute__((unused)))
++{
++    return 0;
++}
++
++static wsrep_status_t dummy_options_set(
++    wsrep_t* w,
++    const char* conf)
++{
++    WSREP_DBUG_ENTER(w);
++    if (WSREP_DUMMY(w)->options) {
++        free(WSREP_DUMMY(w)->options);
++        WSREP_DUMMY(w)->options = NULL;
++    }
++    if (conf) {
++        WSREP_DUMMY(w)->options = strdup(conf);
++    }
++    return WSREP_OK;
++}
++
++static char* dummy_options_get (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_DUMMY(w)->options;
++}
++
++static wsrep_status_t dummy_connect(
++    wsrep_t* w,
++    const char*  name      __attribute__((unused)),
++    const char*  url       __attribute__((unused)),
++    const char*  donor     __attribute__((unused)),
++    wsrep_bool_t bootstrap __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_disconnect(wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_recv(wsrep_t* w,
++                                 void*    recv_ctx __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_pre_commit(
++    wsrep_t* w,
++    const wsrep_conn_id_t   conn_id    __attribute__((unused)),
++    wsrep_ws_handle_t*      ws_handle  __attribute__((unused)),
++    uint32_t                flags      __attribute__((unused)),
++    wsrep_trx_meta_t*       meta       __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_post_commit(
++    wsrep_t* w,
++    wsrep_ws_handle_t*  ws_handle  __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_post_rollback(
++    wsrep_t* w,
++    wsrep_ws_handle_t*  ws_handle  __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_replay_trx(
++    wsrep_t* w,
++    wsrep_ws_handle_t*  ws_handle  __attribute__((unused)),
++    void*               trx_ctx    __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_abort_pre_commit(
++    wsrep_t* w,
++    const wsrep_seqno_t  bf_seqno __attribute__((unused)),
++    const wsrep_trx_id_t trx_id   __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_append_key(
++    wsrep_t* w,
++    wsrep_ws_handle_t*     ws_handle  __attribute__((unused)),
++    const wsrep_key_t*     key        __attribute__((unused)),
++    const size_t           key_num    __attribute__((unused)),
++    const wsrep_key_type_t key_type   __attribute__((unused)),
++    const bool             copy       __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_append_data(
++    wsrep_t* w,
++    wsrep_ws_handle_t*      ws_handle  __attribute__((unused)),
++    const struct wsrep_buf* data       __attribute__((unused)),
++    const size_t            count      __attribute__((unused)),
++    const wsrep_data_type_t type       __attribute__((unused)),
++    const bool              copy       __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_causal_read(
++    wsrep_t* w,
++    wsrep_gtid_t* gtid __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_free_connection(
++    wsrep_t* w,
++    const wsrep_conn_id_t  conn_id   __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_to_execute_start(
++    wsrep_t* w,
++    const wsrep_conn_id_t   conn_id __attribute__((unused)),
++    const wsrep_key_t*      key     __attribute__((unused)),
++    const size_t            key_num __attribute__((unused)),
++    const struct wsrep_buf* data    __attribute__((unused)),
++    const size_t            count   __attribute__((unused)),
++    wsrep_trx_meta_t*       meta    __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_to_execute_end(
++    wsrep_t* w,
++    const wsrep_conn_id_t  conn_id   __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_preordered_collect(
++    wsrep_t*                 w,
++    wsrep_po_handle_t*       handle    __attribute__((unused)),
++    const struct wsrep_buf*  data      __attribute__((unused)),
++    size_t                   count     __attribute__((unused)),
++    wsrep_bool_t             copy      __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_preordered_commit(
++    wsrep_t*                 w,
++    wsrep_po_handle_t*       handle    __attribute__((unused)),
++    const wsrep_uuid_t*      source_id __attribute__((unused)),
++    uint32_t                 flags     __attribute__((unused)),
++    int                      pa_range  __attribute__((unused)),
++    wsrep_bool_t             commit    __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_sst_sent(
++    wsrep_t* w,
++    const wsrep_gtid_t* state_id  __attribute__((unused)),
++    const int           rcode     __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_sst_received(
++    wsrep_t* w,
++    const wsrep_gtid_t* state_id  __attribute__((unused)),
++    const void*         state     __attribute__((unused)),
++    const size_t        state_len __attribute__((unused)),
++    const int           rcode     __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_snapshot(
++    wsrep_t* w,
++    const void*  msg        __attribute__((unused)),
++    const size_t msg_len    __attribute__((unused)),
++    const char*  donor_spec __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static struct wsrep_stats_var dummy_stats[] = {
++    { NULL, WSREP_VAR_STRING, { 0 } }
++};
++
++static struct wsrep_stats_var* dummy_stats_get (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return dummy_stats;
++}
++
++static void dummy_stats_free (
++    wsrep_t* w,
++    struct wsrep_stats_var* stats __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++}
++
++static void dummy_stats_reset (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++}
++
++static wsrep_seqno_t dummy_pause (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return -ENOSYS;
++}
++
++static wsrep_status_t dummy_resume (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_desync (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_NOT_IMPLEMENTED;
++}
++
++static wsrep_status_t dummy_resync (wsrep_t* w)
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static wsrep_status_t dummy_lock (wsrep_t* w,
++                                  const char* s __attribute__((unused)),
++                                  bool        r __attribute__((unused)),
++                                  uint64_t    o __attribute__((unused)),
++                                  int64_t     t __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_NOT_IMPLEMENTED;
++}
++
++static wsrep_status_t dummy_unlock (wsrep_t* w,
++                                    const char* s __attribute__((unused)),
++                                    uint64_t    o __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return WSREP_OK;
++}
++
++static bool dummy_is_locked (wsrep_t* w,
++                             const char*   s __attribute__((unused)),
++                             uint64_t*     o __attribute__((unused)),
++                             wsrep_uuid_t* t __attribute__((unused)))
++{
++    WSREP_DBUG_ENTER(w);
++    return false;
++}
++
++static wsrep_t dummy_iface = {
++    WSREP_INTERFACE_VERSION,
++    &dummy_init,
++    &dummy_capabilities,
++    &dummy_options_set,
++    &dummy_options_get,
++    &dummy_connect,
++    &dummy_disconnect,
++    &dummy_recv,
++    &dummy_pre_commit,
++    &dummy_post_commit,
++    &dummy_post_rollback,
++    &dummy_replay_trx,
++    &dummy_abort_pre_commit,
++    &dummy_append_key,
++    &dummy_append_data,
++    &dummy_causal_read,
++    &dummy_free_connection,
++    &dummy_to_execute_start,
++    &dummy_to_execute_end,
++    &dummy_preordered_collect,
++    &dummy_preordered_commit,
++    &dummy_sst_sent,
++    &dummy_sst_received,
++    &dummy_snapshot,
++    &dummy_stats_get,
++    &dummy_stats_free,
++    &dummy_stats_reset,
++    &dummy_pause,
++    &dummy_resume,
++    &dummy_desync,
++    &dummy_resync,
++    &dummy_lock,
++    &dummy_unlock,
++    &dummy_is_locked,
++    WSREP_NONE,
++    WSREP_INTERFACE_VERSION,
++    "Codership Oy <info@codership.com>",
++    &dummy_free,
++    NULL,
++    NULL
++};
++
++int wsrep_dummy_loader(wsrep_t* w)
++{
++    if (!w)
++        return EINVAL;
++
++    *w = dummy_iface;
++
++    // allocate private context
++    if (!(w->ctx = malloc(sizeof(wsrep_dummy_t))))
++        return ENOMEM;
++
++    // initialize private context
++    WSREP_DUMMY(w)->log_fn = NULL;
++    WSREP_DUMMY(w)->options = NULL;
++
++    return 0;
++}
+diff --git a/wsrep/wsrep_gtid.c b/wsrep/wsrep_gtid.c
+new file mode 100644
+index 0000000..e618c5a
+--- /dev/null
++++ b/wsrep/wsrep_gtid.c
+@@ -0,0 +1,74 @@
++/* Copyright (C) 2013 Codership Oy <info@codersihp.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*! @file Helper functions to deal with GTID string representations */
++
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <inttypes.h>
++
++#include "wsrep_api.h"
++
++/*!
++ * Read GTID from string
++ * @return length of GTID string representation or -EINVAL in case of error
++ */
++int
++wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid)
++{
++    unsigned int offset;
++    char* endptr;
++
++    if ((offset = wsrep_uuid_scan(str, str_len, &gtid->uuid)) > 0 &&
++        offset < str_len && str[offset] == ':') {
++        ++offset;
++        if (offset < str_len)
++        {
++            errno = 0;
++            gtid->seqno = strtoll(str + offset, &endptr, 0);
++
++            if (errno == 0) {
++                offset = endptr - str;
++                return offset;
++            }
++        }
++    }
++    *gtid = WSREP_GTID_UNDEFINED;
++    return -EINVAL;
++}
++
++/*!
++ * Write GTID to string
++ * @return length of GTID stirng representation of -EMSGSIZE if string is too
++ *         short
++ */
++int
++wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len)
++{
++    unsigned int offset, ret;
++    if ((offset = wsrep_uuid_print(&gtid->uuid, str, str_len)) > 0)
++    {
++        ret = snprintf(str + offset, str_len - offset,
++                       ":%" PRId64, gtid->seqno);
++        if (ret <= str_len - offset) {
++            return (offset + ret);
++        }
++
++    }
++
++    return -EMSGSIZE;
++}
+diff --git a/wsrep/wsrep_loader.c b/wsrep/wsrep_loader.c
+new file mode 100644
+index 0000000..c330c77
+--- /dev/null
++++ b/wsrep/wsrep_loader.c
+@@ -0,0 +1,203 @@
++/* Copyright (C) 2009-2011 Codership Oy <info@codersihp.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*! @file wsrep implementation loader */
++
++#include <dlfcn.h>
++#include <errno.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "wsrep_api.h"
++
++// Logging stuff for the loader
++static const char* log_levels[] = {"FATAL", "ERROR", "WARN", "INFO", "DEBUG"};
++
++static void default_logger (wsrep_log_level_t lvl, const char* msg)
++{
++    fprintf (stderr, "wsrep loader: [%s] %s\n", log_levels[lvl], msg);
++}
++
++static wsrep_log_cb_t logger = default_logger;
++
++/**************************************************************************
++ * Library loader
++ **************************************************************************/
++
++static int verify(const wsrep_t *wh, const char *iface_ver)
++{
++    const size_t msg_len = 128;
++    char msg[128];
++
++#define VERIFY(_p) if (!(_p)) {                                       \
++        snprintf(msg, msg_len, "wsrep_load(): verify(): %s\n", # _p); \
++        logger (WSREP_LOG_ERROR, msg);                                \
++        return EINVAL;                                                \
++    }
++
++    VERIFY(wh);
++    VERIFY(wh->version);
++
++    if (strcmp(wh->version, iface_ver)) {
++        snprintf (msg, msg_len,
++                  "provider interface version mismatch: need '%s', found '%s'",
++                  iface_ver, wh->version);
++        logger (WSREP_LOG_ERROR, msg);
++        return EINVAL;
++    }
++
++    VERIFY(wh->init);
++    VERIFY(wh->options_set);
++    VERIFY(wh->options_get);
++    VERIFY(wh->connect);
++    VERIFY(wh->disconnect);
++    VERIFY(wh->recv);
++    VERIFY(wh->pre_commit);
++    VERIFY(wh->post_commit);
++    VERIFY(wh->post_rollback);
++    VERIFY(wh->replay_trx);
++    VERIFY(wh->abort_pre_commit);
++    VERIFY(wh->append_key);
++    VERIFY(wh->append_data);
++    VERIFY(wh->free_connection);
++    VERIFY(wh->to_execute_start);
++    VERIFY(wh->to_execute_end);
++    VERIFY(wh->preordered_collect);
++    VERIFY(wh->preordered_commit);
++    VERIFY(wh->sst_sent);
++    VERIFY(wh->sst_received);
++    VERIFY(wh->stats_get);
++    VERIFY(wh->stats_free);
++    VERIFY(wh->stats_reset);
++    VERIFY(wh->pause);
++    VERIFY(wh->resume);
++    VERIFY(wh->desync);
++    VERIFY(wh->resync);
++    VERIFY(wh->lock);
++    VERIFY(wh->unlock);
++    VERIFY(wh->is_locked);
++    VERIFY(wh->provider_name);
++    VERIFY(wh->provider_version);
++    VERIFY(wh->provider_vendor);
++    VERIFY(wh->free);
++    return 0;
++}
++
++typedef int (*wsrep_loader_fun)(wsrep_t*);
++
++static wsrep_loader_fun wsrep_dlf(void *dlh, const char *sym)
++{
++    union {
++        wsrep_loader_fun dlfun;
++        void *obj;
++    } alias;
++    alias.obj = dlsym(dlh, sym);
++    return alias.dlfun;
++}
++
++extern int wsrep_dummy_loader(wsrep_t *w);
++
++int wsrep_load(const char *spec, wsrep_t **hptr, wsrep_log_cb_t log_cb)
++{
++    int ret = 0;
++    void *dlh = NULL;
++    wsrep_loader_fun dlfun;
++    const size_t msg_len = 1024;
++    char msg[1024 + 1];
++    msg[msg_len] = 0;
++
++    if (NULL != log_cb)
++        logger = log_cb;
++
++    if (!(spec && hptr))
++        return EINVAL;
++
++    snprintf (msg, msg_len,
++              "wsrep_load(): loading provider library '%s'", spec);
++    logger (WSREP_LOG_INFO, msg);
++
++    if (!(*hptr = malloc(sizeof(wsrep_t)))) {
++        logger (WSREP_LOG_FATAL, "wsrep_load(): out of memory");
++        return ENOMEM;
++    }
++
++    if (!spec || strcmp(spec, WSREP_NONE) == 0) {
++        if ((ret = wsrep_dummy_loader(*hptr)) != 0) {
++            free (*hptr);
++            *hptr = NULL;
++        }
++        return ret;
++    }
++
++    if (!(dlh = dlopen(spec, RTLD_NOW | RTLD_LOCAL))) {
++        snprintf(msg, msg_len, "wsrep_load(): dlopen(): %s", dlerror());
++        logger (WSREP_LOG_ERROR, msg);
++        ret = EINVAL;
++        goto out;
++    }
++
++    if (!(dlfun = wsrep_dlf(dlh, "wsrep_loader"))) {
++        ret = EINVAL;
++        goto out;
++    }
++
++    if ((ret = (*dlfun)(*hptr)) != 0) {
++        snprintf(msg, msg_len, "wsrep_load(): loader failed: %s",
++                 strerror(ret));
++        logger (WSREP_LOG_ERROR, msg);
++        goto out;
++    }
++
++    if ((ret = verify(*hptr, WSREP_INTERFACE_VERSION)) != 0) {
++        snprintf (msg, msg_len,
++                  "wsrep_load(): interface version mismatch: my version %s, "
++                  "provider version %s", WSREP_INTERFACE_VERSION,
++                  (*hptr)->version);
++        logger (WSREP_LOG_ERROR, msg);
++        goto out;
++    }
++
++    (*hptr)->dlh = dlh;
++
++out:
++    if (ret != 0) {
++        if (dlh) dlclose(dlh);
++        free(*hptr);
++        *hptr = NULL;
++    } else {
++        snprintf (msg, msg_len,
++                  "wsrep_load(): %s %s by %s loaded successfully.",
++                  (*hptr)->provider_name, (*hptr)->provider_version,
++                  (*hptr)->provider_vendor);
++        logger (WSREP_LOG_INFO, msg);
++    }
++
++    return ret;
++}
++
++void wsrep_unload(wsrep_t *hptr)
++{
++    if (!hptr) {
++        logger (WSREP_LOG_WARN, "wsrep_unload(): null pointer.");
++    } else {
++        if (hptr->free)
++            hptr->free(hptr);
++        if (hptr->dlh)
++            dlclose(hptr->dlh);
++        free(hptr);
++    }
++}
++
+diff --git a/wsrep/wsrep_uuid.c b/wsrep/wsrep_uuid.c
+new file mode 100644
+index 0000000..baa95b2
+--- /dev/null
++++ b/wsrep/wsrep_uuid.c
+@@ -0,0 +1,83 @@
++/* Copyright (C) 2009 Codership Oy <info@codersihp.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; version 2 of the License.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*! @file Helper functions to deal with history UUID string representations */
++
++#include <errno.h>
++#include <ctype.h>
++#include <stdio.h>
++
++#include "wsrep_api.h"
++
++/*!
++ * Read UUID from string
++ * @return length of UUID string representation or -EINVAL in case of error
++ */
++int
++wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid)
++{
++    unsigned int uuid_len  = 0;
++    unsigned int uuid_offt = 0;
++
++    while (uuid_len + 1 < str_len) {
++        /* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10
++         * which means
++         *     (uuid_offt >> 1) == 2, 3, 4, 5,
++         * which in turn means
++         *     (uuid_offt >> 1) - 2 <= 3
++         * since it is always >= 0, because uuid_offt is unsigned */
++        if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') {
++            // skip dashes after 4th, 6th, 8th and 10th positions
++            uuid_len += 1;
++            continue;
++        }
++
++        if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) {
++            // got hex digit, scan another byte to uuid, increment uuid_offt
++            sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt);
++            uuid_len  += 2;
++            uuid_offt += 1;
++            if (sizeof (uuid->data) == uuid_offt)
++                return uuid_len;
++        }
++        else {
++            break;
++        }
++    }
++
++    *uuid = WSREP_UUID_UNDEFINED;
++    return -EINVAL;
++}
++
++/*!
++ * Write UUID to string
++ * @return length of UUID string representation or -EMSGSIZE if string is too
++ *         short
++ */
++int
++wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len)
++{
++    if (str_len > 36) {
++        const unsigned char* u = uuid->data;
++        return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
++                        "%02x%02x-%02x%02x%02x%02x%02x%02x",
++                        u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7],
++                        u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15]);
++    }
++    else {
++        return -EMSGSIZE;
++    }
++}
diff --git a/mysql.spec b/mysql.spec
new file mode 100644 (file)
index 0000000..c8ec694
--- /dev/null
@@ -0,0 +1,2117 @@
+# Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
+# MA  02110-1301  USA.
+
+##############################################################################
+# Some common macro definitions
+##############################################################################
+
+# NOTE: "vendor" is used in upgrade/downgrade check, so you can't
+# change these, has to be exactly as is.
+%global mysql_old_vendor        MySQL AB
+%global mysql_vendor_2          Sun Microsystems, Inc.
+%global mysql_vendor            Oracle and/or its affiliates
+
+%global mysql_version   5.6.23
+%global wsrep_version   25.10
+%global wsrep_revision  XXXX
+
+%global mysqld_user     mysql
+%global mysqld_group    mysql
+%global mysqldatadir    /var/lib/mysql
+
+%global release         %{wsrep_version}
+%global short_product_tag 5.6
+
+#
+# Macros we use which are not available in all supported versions of RPM
+#
+# - defined/undefined are missing on RHEL4
+#
+%if %{expand:%{?defined:0}%{!?defined:1}}
+%define defined()       %{expand:%%{?%{1}:1}%%{!?%{1}:0}}
+%endif
+%if %{expand:%{?undefined:0}%{!?undefined:1}}
+%define undefined()     %{expand:%%{?%{1}:0}%%{!?%{1}:1}}
+%endif
+
+# ----------------------------------------------------------------------------
+# RPM build tools now automatically detect Perl module dependencies.  This
+# detection causes problems as it is broken in some versions, and it also
+# provides unwanted dependencies from mandatory scripts in our package.
+# It might not be possible to disable this in all versions of RPM, but here we
+# try anyway.  We keep the "AutoReqProv: no" for the "test" sub package, as
+# disabling here might fail, and that package has the most problems.
+# See:
+#  http://fedoraproject.org/wiki/Packaging/Perl#Filtering_Requires:_and_Provides
+#  http://www.wideopen.com/archives/rpm-list/2002-October/msg00343.html
+# ----------------------------------------------------------------------------
+%undefine __perl_provides
+%undefine __perl_requires
+
+##############################################################################
+# Command line handling
+##############################################################################
+#
+# To set options:
+#
+#   $ rpmbuild --define="option <x>" ...
+#
+
+# ----------------------------------------------------------------------------
+# Commercial builds
+# ----------------------------------------------------------------------------
+%if %{undefined commercial}
+%define commercial 0
+%endif
+
+# ----------------------------------------------------------------------------
+# Source name
+# ----------------------------------------------------------------------------
+%if %{undefined src_base}
+#%define src_base mysql-wsrep
+%define src_base mysql
+%endif
+#%define src_dir %{src_base}-%{mysql_version}-%{wsrep_version}
+%define src_dir %{src_base}-%{mysql_version}
+
+# ----------------------------------------------------------------------------
+# Feature set (storage engines, options).  Default to community (everything)
+# ----------------------------------------------------------------------------
+%if %{undefined feature_set}
+%define feature_set community
+%endif
+
+# ----------------------------------------------------------------------------
+# Server comment strings
+# ----------------------------------------------------------------------------
+%if %{undefined compilation_comment_debug}
+%define compilation_comment_debug       MySQL Community Server - Debug (GPL)
+%endif
+%if %{undefined compilation_comment_release}
+%define compilation_comment_release     MySQL Community Server (GPL)
+%endif
+
+# ----------------------------------------------------------------------------
+# Product and server suffixes
+# ----------------------------------------------------------------------------
+%if %{undefined product_suffix}
+  %if %{defined short_product_tag}
+    %define product_suffix      -%{short_product_tag}
+  %else
+    %define product_suffix      %{nil}
+  %endif
+%endif
+
+%if %{undefined server_suffix}
+%define server_suffix   %{nil}
+%endif
+
+# ----------------------------------------------------------------------------
+# Distribution support
+# ----------------------------------------------------------------------------
+
+# Disable post build checks for time being.
+BuildConflicts: post-build-checks
+
+BuildRequires: gcc-c++ ncurses-devel perl zlib-devel cmake libaio-devel bison flex
+
+%if 0%{?rhel} == 6 || 0%{?rhel} == 7 || 0%{?fedora} == 20 || 0%{?fedora} == 21
+BuildRequires: time
+%endif
+
+%if 0%{?suse_version}
+%if 0%{?suse_version} == 1110
+BuildRequires: gdbm-devel gperf openldap2-client procps pwdutils
+%endif
+%if 0%{?suse_version} == 1310 || 0%{?suse_version} == 1315 || 0%{?suse_version} == 1320
+BuildRequires: gperf procps time
+%endif
+%endif
+
+# Define dist tag if not given by platform
+%if %{undefined dist}
+  # For suse versions see:
+  # https://en.opensuse.org/openSUSE:Build_Service_cross_distribution_howto
+  %if 0%{?suse_version} == 1110
+    %define dist .sle11
+  %endif
+  %if 0%{?suse_version} == 1310
+    %define dist .suse13.1
+  %endif
+  %if 0%{?suse_version} == 1315
+    %define dist .sle12
+  %endif
+  %if 0%{?suse_version} == 1320
+    %define dist .suse13.2
+  %endif
+  # Still missing?
+  %if %{undefined dist}
+    %define dist .DIST
+  %endif
+%endif
+
+
+# Avoid debuginfo RPMs, leaves binaries unstripped
+%define debug_package   %{nil}
+
+# Hack to work around bug in RHEL5 __os_install_post macro, wrong inverted
+# test for __debug_package
+%define __strip         /bin/true
+
+# ----------------------------------------------------------------------------
+# Support optional "tcmalloc" library (experimental)
+# ----------------------------------------------------------------------------
+%if %{defined malloc_lib_target}
+%define WITH_TCMALLOC 1
+%else
+%define WITH_TCMALLOC 0
+%endif
+
+##############################################################################
+# Configuration based upon above user input, not to be set directly
+##############################################################################
+
+%if 0%{?commercial}
+%define license_files_server    %{src_dir}/LICENSE.mysql
+%define license_type            Commercial
+%else
+%define license_files_server    COPYING README
+%define license_type            GPL
+%endif
+
+##############################################################################
+# Main spec file section
+##############################################################################
+
+Name:           MySQL%{product_suffix}
+Summary:        MySQL: a very fast and reliable SQL database server
+Group:          Applications/Databases
+Version:        5.6.23_wsrep_25.10
+Release:        %{release}%{?dist}~mos8.0.1
+# Distribution:   %{distro_description}
+License:        Copyright (c) 2000, 2015, %{mysql_vendor}. All rights reserved. Under %{license_type} license as shown in the Description field.
+Source:         mysql-5.6.23.tar.gz
+URL:            http://www.mysql.com/
+Packager:       Codership Oy <info@galeracluster.com>
+Vendor:         %{mysql_vendor}
+# BuildRequires:  %{distro_buildreq}
+#wsrep_patch_tag
+Patch0:         fix-man-page-links.patch
+Patch1:         scripts__mysqld_safe.sh__signals.patch
+Patch2:         disable_tests.patch
+Patch3:         fix_standalone_tests.patch
+Patch4:         spelling.patch
+Patch5:         mysql-5.6.23_wsrep_25.10.patch
+Patch6:         wsrep_sst_mysqldump.patch
+
+# Regression tests may take a long time, override the default to skip them 
+%{!?runselftest:%global runselftest 0}
+
+# Think about what you use here since the first step is to
+# run a rm -rf
+BuildRoot:    %{_tmppath}/%{name}-%{version}-build
+
+# From the manual
+%description
+The MySQL(TM) software delivers a very fast, multi-threaded, multi-user,
+and robust SQL (Structured Query Language) database server. MySQL Server
+is intended for mission-critical, heavy-load production systems as well
+as for embedding into mass-deployed software. MySQL is a trademark of
+%{mysql_vendor}
+
+The MySQL software has Dual Licensing, which means you can use the MySQL
+software free of charge under the GNU General Public License
+(http://www.gnu.org/licenses/). You can also purchase commercial MySQL
+licenses from %{mysql_vendor} if you do not wish to be bound by the terms of
+the GPL. See the chapter "Licensing and Support" in the manual for
+further info.
+
+The MySQL web site (http://www.mysql.com/) provides the latest
+news and information about the MySQL software. Also please see the
+documentation and the manual for more information.
+
+##############################################################################
+# Sub package definition
+##############################################################################
+
+%package -n mysql-wsrep%{product_suffix}
+Summary:        MySQL: meta package for a server+client setup
+Group:          Applications/Databases
+Requires:       mysql-wsrep-server%{product_suffix}
+Requires:       mysql-wsrep-client%{product_suffix}
+
+%description -n mysql-wsrep%{product_suffix}
+This meta package ensures the installation of a MySQL server and the necessary
+client programs for operation and administration. It does not itself
+contain those files but rather causes the installation of the subpackages
+"mysql-wsrep-server%{product_suffix}" and "mysql-wsrep-client%{product_suffix}".
+As indicated in the name, the server is built with the "wsrep" plugin so that
+it can be a node in a MySQL Galera Cluster.
+
+# ----------------------------------------------------------------------------
+
+%package -n mysql-wsrep-server%{product_suffix}
+Summary:        MySQL: a very fast and reliable SQL database server
+Group:          Applications/Databases
+# Distro requirements
+# RedHat
+%if 0%{?fedora} || 0%{?rhel}
+Requires:       chkconfig coreutils grep procps shadow-utils net-tools rsync lsof
+%if 0%{?rhel} == 7 || 0%{?fedora} >= 20
+Requires: perl-Data-Dumper
+%endif
+%endif
+# SUSE
+%if 0%{?suse_version}
+Requires: aaa_base coreutils grep procps rsync lsof
+%if 0%{suse_version} == 1110
+Requires: pwdutils
+%endif
+%endif
+
+%if 0%{?commercial}
+Obsoletes:      MySQL-server
+%else
+Obsoletes:      MySQL-server-advanced
+%endif
+Obsoletes:      mysql-server < %{version}-%{release}
+Obsoletes:      mysql-server-advanced
+Obsoletes:      MySQL-server-classic MySQL-server-community MySQL-server-enterprise
+Obsoletes:      MySQL-server-advanced-gpl MySQL-server-enterprise-gpl
+Obsoletes:      mariadb-libs mariadb-server
+Provides:       mysql-server = %{version}-%{release}
+Provides:       mysql-server%{?_isa} = %{version}-%{release}
+
+%description -n mysql-wsrep-server%{product_suffix}
+The MySQL(TM) software delivers a very fast, multi-threaded, multi-user,
+and robust SQL (Structured Query Language) database server. MySQL Server
+is intended for mission-critical, heavy-load production systems as well
+as for embedding into mass-deployed software. MySQL is a trademark of
+%{mysql_vendor}
+
+The MySQL software has Dual Licensing, which means you can use the MySQL
+software free of charge under the GNU General Public License
+(http://www.gnu.org/licenses/). You can also purchase commercial MySQL
+licenses from %{mysql_vendor} if you do not wish to be bound by the terms of
+the GPL. See the chapter "Licensing and Support" in the manual for
+further info.
+
+The MySQL web site (http://www.mysql.com/) provides the latest news and
+information about the MySQL software.  Also please see the documentation
+and the manual for more information.
+
+This package includes the MySQL server binary as well as related utilities
+to run and administer a MySQL server.
+
+Built with wsrep patch %{wsrep_version}.
+
+If you want to access and work with the database, you have to install
+package "mysql-wsrep-client%{product_suffix}" as well!
+
+# ----------------------------------------------------------------------------
+%package -n mysql-wsrep-client%{product_suffix}
+Summary:        MySQL - Client
+Group:          Applications/Databases
+%if 0%{?commercial}
+Obsoletes:      MySQL-client
+%else
+Obsoletes:      MySQL-client-advanced
+%endif
+Obsoletes:      mysql < %{version}-%{release}
+Obsoletes:      mysql-advanced < %{version}-%{release}
+Obsoletes:      MySQL-client-classic MySQL-client-community MySQL-client-enterprise
+Obsoletes:      MySQL-client-advanced-gpl MySQL-client-enterprise-gpl
+Provides:       mysql = %{version}-%{release}
+Provides:       mysql%{?_isa} = %{version}-%{release}
+
+%description -n mysql-wsrep-client%{product_suffix}
+This package contains the standard MySQL clients and administration tools.
+
+For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+
+# ----------------------------------------------------------------------------
+%package -n mysql-wsrep-test%{product_suffix}
+Summary:        MySQL - Test suite
+Group:          Applications/Databases
+%if 0%{?commercial}
+#Requires:       MySQL-client-advanced perl
+Requires:       mysql-wsrep-client%{product_suffix} perl
+Obsoletes:      MySQL-test
+%else
+#Requires:       MySQL-client perl
+Requires:       mysql-wsrep-client%{product_suffix} perl
+Obsoletes:      MySQL-test-advanced
+%endif
+Obsoletes:      mysql-test < %{version}-%{release}
+Obsoletes:      mysql-test-advanced
+Obsoletes:      MySQL-test-classic MySQL-test-community MySQL-test-enterprise
+Obsoletes:      MySQL-test-advanced-gpl MySQL-test-enterprise-gpl
+Provides:       mysql-test = %{version}-%{release}
+Provides:       mysql-test%{?_isa} = %{version}-%{release}
+AutoReqProv:    no
+
+%description -n mysql-wsrep-test%{product_suffix}
+This package contains the MySQL regression test suite.
+
+For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+
+# ----------------------------------------------------------------------------
+%package -n mysql-wsrep-devel%{product_suffix}
+Summary:        MySQL - Development header files and libraries
+Group:          Applications/Databases
+%if 0%{?commercial}
+Obsoletes:      MySQL-devel
+%else
+Obsoletes:      MySQL-devel-advanced
+%endif
+Obsoletes:      mysql-devel < %{version}-%{release}
+Obsoletes:      mysql-embedded-devel mysql-devel-advanced mysql-embedded-devel-advanced
+Obsoletes:      MySQL-devel-classic MySQL-devel-community MySQL-devel-enterprise
+Obsoletes:      MySQL-devel-advanced-gpl MySQL-devel-enterprise-gpl
+Provides:       mysql-devel = %{version}-%{release}
+Provides:       mysql-devel%{?_isa} = %{version}-%{release}
+
+%description -n mysql-wsrep-devel%{product_suffix}
+This package contains the development header files and libraries necessary
+to develop MySQL client applications.
+
+For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
+
+# ----------------------------------------------------------------------------
+%package -n mysql-wsrep-shared%{product_suffix}
+Summary:        MySQL - Shared libraries
+Group:          Applications/Databases
+%if 0%{?commercial}
+Obsoletes:      MySQL-shared
+%else
+Obsoletes:      MySQL-shared-advanced
+%endif
+Obsoletes:      MySQL-shared-standard MySQL-shared-pro
+Obsoletes:      MySQL-shared-pro-cert MySQL-shared-pro-gpl
+Obsoletes:      MySQL-shared-pro-gpl-cert
+Obsoletes:      MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise
+Obsoletes:      MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl
+
+%description -n mysql-wsrep-shared%{product_suffix}
+This package contains the shared libraries (*.so*) which certain languages
+and applications need to dynamically load and use MySQL.
+
+##############################################################################
+%prep
+%setup -q -T -a 0 -c -n %{src_dir}
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+#wsrep_apply_patch_tag
+##############################################################################
+%build
+
+# Fail quickly and obviously if user tries to build as root
+%if %runselftest
+    if [ x"`id -u`" = x0 ]; then
+        echo "The MySQL regression tests may fail if run as root."
+        echo "If you really need to build the RPM as root, use"
+        echo "--define='runselftest 0' to skip the regression tests."
+        exit 1
+    fi
+%endif
+
+# Be strict about variables, bail at earliest opportunity, etc.
+set -eu
+
+# Optional package files
+touch optional-files-devel
+
+#
+# Set environment in order of preference, MYSQL_BUILD_* first, then variable
+# name, finally a default.  RPM_OPT_FLAGS is assumed to be a part of the
+# default RPM build environment.
+#
+
+# This is a hack, $RPM_OPT_FLAGS on ia64 hosts contains flags which break
+# the compile in cmd-line-utils/libedit - needs investigation, but for now
+# we simply unset it and use those specified directly in cmake.
+%if "%{_arch}" == "ia64"
+RPM_OPT_FLAGS=
+%endif
+
+export PATH=${MYSQL_BUILD_PATH:-$PATH}
+export CC=${MYSQL_BUILD_CC:-${CC:-gcc}}
+export CXX=${MYSQL_BUILD_CXX:-${CXX:-g++}}
+export CFLAGS=${MYSQL_BUILD_CFLAGS:-${CFLAGS:-$RPM_OPT_FLAGS}}
+export CXXFLAGS=${MYSQL_BUILD_CXXFLAGS:-${CXXFLAGS:-$RPM_OPT_FLAGS -felide-constructors}}
+export LDFLAGS=${MYSQL_BUILD_LDFLAGS:-${LDFLAGS:-}}
+export CMAKE=${MYSQL_BUILD_CMAKE:-${CMAKE:-cmake}}
+export MAKE_JFLAG=${MYSQL_BUILD_MAKE_JFLAG:--j$(ncpu=$(cat /proc/cpuinfo | grep processor | wc -l) && echo $(($ncpu > 4 ? 4 : $ncpu)))}
+
+# By default, a build will include the bundeled "yaSSL" library for SSL.
+# However, there may be a need to override.
+# Protect against undefined variables if there is no override option.
+%if %{undefined with_ssl}
+%define ssl_option   %{nil}
+%else
+%define ssl_option   -DWITH_SSL=%{with_ssl}
+%endif
+
+# Build debug mysqld and libmysqld.a
+mkdir debug
+(
+  cd debug
+  # Attempt to remove any optimisation flags from the debug build
+  CFLAGS=`echo " ${CFLAGS} " | \
+            sed -e 's/ -O[0-9]* / /' \
+                -e 's/-Wp,-D_FORTIFY_SOURCE=2/ /' \
+                -e 's/-D_FORTIFY_SOURCE=2/ /' \
+                -e 's/ -unroll2 / /' \
+                -e 's/ -ip / /' \
+                -e 's/^ //' \
+                -e 's/ $//'`
+  CXXFLAGS=`echo " ${CXXFLAGS} " | \
+              sed -e 's/ -O[0-9]* / /' \
+                  -e 's/-Wp,-D_FORTIFY_SOURCE=2/ /' \
+                  -e 's/-D_FORTIFY_SOURCE=2/ /' \
+                  -e 's/ -unroll2 / /' \
+                  -e 's/ -ip / /' \
+                  -e 's/^ //' \
+                  -e 's/ $//'`
+  # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before
+  # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM
+  ${CMAKE} ../ -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
+           -DCMAKE_BUILD_TYPE=Debug \
+           -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
+           -DFEATURE_SET="%{feature_set}" \
+           %{ssl_option} \
+           -DCOMPILATION_COMMENT="%{compilation_comment_debug}" \
+           -DMYSQL_SERVER_SUFFIX="%{server_suffix}" \
+           -DWITH_WSREP=1 \
+           -DWSREP_VERSION="%{wsrep_version}" \
+           -DWSREP_REVISION="%{wsrep_revision}"
+  echo BEGIN_DEBUG_CONFIG ; egrep '^#define' include/config.h ; echo END_DEBUG_CONFIG
+  make ${MAKE_JFLAG} VERBOSE=1
+)
+# Build full release
+mkdir release
+(
+  cd release
+  # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before
+  # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM
+  ${CMAKE} ../ -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \
+           -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+           -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
+           -DFEATURE_SET="%{feature_set}" \
+           %{ssl_option} \
+           -DCOMPILATION_COMMENT="%{compilation_comment_release}" \
+           -DMYSQL_SERVER_SUFFIX="%{server_suffix}" \
+           -DWITH_WSREP=1 \
+           -DWSREP_VERSION="%{wsrep_version}" \
+           -DWSREP_REVISION="%{wsrep_revision}"
+  echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG
+  make ${MAKE_JFLAG} VERBOSE=1
+)
+
+%if %runselftest
+  MTR_BUILD_THREAD=auto
+  export MTR_BUILD_THREAD
+
+  (cd release && make test-bt-fast || true)
+%endif
+
+##############################################################################
+%install
+
+RBR=$RPM_BUILD_ROOT
+MBD=$RPM_BUILD_DIR/%{src_dir}
+
+# Ensure that needed directories exists
+install -d $RBR%{_sysconfdir}/{logrotate.d,init.d}
+install -d $RBR%{mysqldatadir}/mysql
+install -d $RBR%{_datadir}/mysql-test
+install -d $RBR%{_datadir}/mysql/SELinux/RHEL4
+install -d $RBR%{_includedir}
+install -d $RBR%{_libdir}
+install -d $RBR%{_mandir}
+install -d $RBR%{_sbindir}
+
+mkdir -p $RBR%{_sysconfdir}/my.cnf.d
+
+# Install all binaries
+(
+  cd $MBD/release
+  make DESTDIR=$RBR install
+)
+
+# FIXME: at some point we should stop doing this and just install everything
+# FIXME: directly into %{_libdir}/mysql - perhaps at the same time as renaming
+# FIXME: the shared libraries to use libmysql*-$major.$minor.so syntax
+mv -v $RBR/%{_libdir}/*.a $RBR/%{_libdir}/mysql/
+
+# Install logrotate and autostart
+install -m 644 $MBD/release/support-files/mysql-log-rotate $RBR%{_sysconfdir}/logrotate.d/mysql
+install -m 755 $MBD/release/support-files/mysql.server $RBR%{_sysconfdir}/init.d/mysql
+
+# Create a symlink "rcmysql", pointing to the init.script. SuSE users
+# will appreciate that, as all services usually offer this.
+ln -sf %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql
+
+# Create a wsrep_sst_rsync_wan symlink.
+install -d $RBR%{_bindir}
+ln -sf wsrep_sst_rsync $RBR%{_bindir}/wsrep_sst_rsync_wan
+
+# Touch the place where the my.cnf config file might be located
+# Just to make sure it's in the file list and marked as a config file
+touch $RBR%{_sysconfdir}/my.cnf
+touch $RBR%{_sysconfdir}/wsrep.cnf
+
+
+# Install SELinux files in datadir
+install -m 600 $MBD/support-files/RHEL4-SElinux/mysql.{fc,te} \
+  $RBR%{_datadir}/mysql/SELinux/RHEL4
+
+%if %{WITH_TCMALLOC}
+# Even though this is a shared library, put it under /usr/lib*/mysql, so it
+# doesn't conflict with possible shared lib by the same name in /usr/lib*.  See
+# `mysql_config --variable=pkglibdir` and mysqld_safe for how this is used.
+install -m 644 "%{malloc_lib_source}" \
+  "$RBR%{_libdir}/mysql/%{malloc_lib_target}"
+%endif
+
+# Remove man pages we explicitly do not want to package, avoids 'unpackaged
+# files' warning.
+# This has become obsolete:  rm -f $RBR%{_mandir}/man1/make_win_bin_dist.1*
+
+##############################################################################
+#  Post processing actions, i.e. when installed
+##############################################################################
+
+%pre -n mysql-wsrep-server%{product_suffix}
+# This is the code running at the beginning of a RPM upgrade action,
+# before replacing the old files with the new ones.
+
+# ATTENTION: Parts of this are duplicated in the "triggerpostun" !
+
+# There are users who deviate from the default file system layout.
+# Check local settings to support them.
+if [ -x %{_bindir}/my_print_defaults ]
+then
+  mysql_datadir=`%{_bindir}/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p'`
+  PID_FILE_PATT=`%{_bindir}/my_print_defaults server mysqld | grep '^--pid-file=' | sed -n 's/--pid-file=//p'`
+fi
+if [ -z "$mysql_datadir" ]
+then
+  mysql_datadir=%{mysqldatadir}
+fi
+if [ -z "$PID_FILE_PATT" ]
+then
+  PID_FILE_PATT="$mysql_datadir/*.pid"
+fi
+
+# Check if we can safely upgrade.  An upgrade is only safe if it's from one
+# of our RPMs in the same version family.
+
+# Handle both ways of spelling the capability.
+installed=`rpm -q --whatprovides mysql-server 2> /dev/null`
+if [ $? -ne 0 -o -z "$installed" ]; then
+  installed=`rpm -q --whatprovides MySQL-server 2> /dev/null`
+fi
+if [ $? -eq 0 -a -n "$installed" ]; then
+  installed=`echo $installed | sed 's/\([^ ]*\) .*/\1/'` # Tests have shown duplicated package names
+  vendor=`rpm -q --queryformat='%{VENDOR}' "$installed" 2>&1`
+  version=`rpm -q --queryformat='%{VERSION}' "$installed" 2>&1`
+  myoldvendor='%{mysql_old_vendor}'
+  myvendor_2='%{mysql_vendor_2}'
+  myvendor='%{mysql_vendor}'
+  myversion='%{mysql_version}'
+
+  old_family=`echo $version \
+    | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'`
+  new_family=`echo $myversion \
+    | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'`
+
+  [ -z "$vendor" ] && vendor='<unknown>'
+  [ -z "$old_family" ] && old_family="<unrecognized version $version>"
+  [ -z "$new_family" ] && new_family="<bad package specification: version $myversion>"
+
+  error_text=
+  if [ "$vendor" != "$myoldvendor" \
+    -a "$vendor" != "$myvendor_2" \
+    -a "$vendor" != "$myvendor" ]; then
+    error_text="$error_text
+The current MySQL server package is provided by a different
+vendor ($vendor) than $myoldvendor, $myvendor_2, or $myvendor.
+Some files may be installed to different locations, including log
+files and the service startup script in %{_sysconfdir}/init.d/.
+"
+  fi
+
+  if [ "$old_family" != "$new_family" ]; then
+    error_text="$error_text
+Upgrading directly from MySQL $old_family to MySQL $new_family may not
+be safe in all cases.  A manual dump and restore using mysqldump is
+recommended.  It is important to review the MySQL manual's Upgrading
+section for version-specific incompatibilities.
+"
+  fi
+
+  if [ -n "$error_text" ]; then
+    cat <<HERE >&2
+
+******************************************************************
+A MySQL server package ($installed) is installed.
+$error_text
+A manual upgrade is required.
+
+- Ensure that you have a complete, working backup of your data and my.cnf
+  files
+- Shut down the MySQL server cleanly
+- Remove the existing MySQL packages.  Usually this command will
+  list the packages you should remove:
+  rpm -qa | grep -i '^mysql-'
+
+  You may choose to use 'rpm --nodeps -ev <package-name>' to remove
+  the package which contains the mysqlclient shared library.  The
+  library will be reinstalled by the MySQL-shared-compat package.
+- Install the new MySQL packages supplied by $myvendor
+- Ensure that the MySQL server is started
+- Run the 'mysql_upgrade' program
+
+This is a brief description of the upgrade process.  Important details
+can be found in the MySQL manual, in the Upgrading section.
+******************************************************************
+HERE
+    exit 1
+  fi
+fi
+
+# We assume that if there is exactly one ".pid" file,
+# it contains the valid PID of a running MySQL server.
+NR_PID_FILES=`ls -1 $PID_FILE_PATT 2>/dev/null | wc -l`
+case $NR_PID_FILES in
+       0 ) SERVER_TO_START=''  ;;  # No "*.pid" file == no running server
+       1 ) SERVER_TO_START='true' ;;
+       * ) SERVER_TO_START=''      # Situation not clear
+           SEVERAL_PID_FILES=true ;;
+esac
+# That logic may be debated: We might check whether it is non-empty,
+# contains exactly one number (possibly a PID), and whether "ps" finds it.
+# OTOH, if there is no such process, it means a crash without a cleanup -
+# is that a reason not to start a new server after upgrade?
+
+STATUS_FILE=$mysql_datadir/RPM_UPGRADE_MARKER
+
+if [ -f $STATUS_FILE ]; then
+       echo "Some previous upgrade was not finished:"
+       ls -ld $STATUS_FILE
+       echo "Please check its status, then do"
+       echo "    rm $STATUS_FILE"
+       echo "before repeating the MySQL upgrade."
+       exit 1
+elif [ -n "$SEVERAL_PID_FILES" ] ; then
+       echo "You have more than one PID file:"
+       ls -ld $PID_FILE_PATT
+       echo "Please check which one (if any) corresponds to a running server"
+       echo "and delete all others before repeating the MySQL upgrade."
+       exit 1
+fi
+
+NEW_VERSION=%{mysql_version}-%{release}
+
+# The "pre" section code is also run on a first installation,
+# when there  is no data directory yet. Protect against error messages.
+# Check for the existence of subdirectory "mysql/", the database of system
+# tables like "mysql.user".
+if [ -d $mysql_datadir/mysql ] ; then
+        echo "MySQL RPM upgrade to version $NEW_VERSION"  > $STATUS_FILE
+        echo "'pre' step running at `date`"          >> $STATUS_FILE
+        echo                                         >> $STATUS_FILE
+        fcount=`ls -ltr $mysql_datadir/*.err 2>/dev/null | wc -l`
+        if [ $fcount -gt 0 ] ; then
+             echo "ERR file(s):"                          >> $STATUS_FILE
+             ls -ltr $mysql_datadir/*.err                 >> $STATUS_FILE
+             echo                                         >> $STATUS_FILE
+             echo "Latest 'Version' line in latest file:" >> $STATUS_FILE
+             grep '^Version' `ls -tr $mysql_datadir/*.err | tail -1` | \
+                tail -1                              >> $STATUS_FILE
+             echo                                         >> $STATUS_FILE
+        fi
+
+       if [ -n "$SERVER_TO_START" ] ; then
+               # There is only one PID file, race possibility ignored
+               echo "PID file:"                           >> $STATUS_FILE
+               ls -l   $PID_FILE_PATT                     >> $STATUS_FILE
+               cat     $PID_FILE_PATT                     >> $STATUS_FILE
+               echo                                       >> $STATUS_FILE
+               echo "Server process:"                     >> $STATUS_FILE
+               ps -fp `cat $PID_FILE_PATT`                >> $STATUS_FILE
+               echo                                       >> $STATUS_FILE
+               echo "SERVER_TO_START=$SERVER_TO_START"    >> $STATUS_FILE
+       else
+               # Take a note we checked it ...
+               echo "PID file:"                           >> $STATUS_FILE
+               ls -l   $PID_FILE_PATT                     >> $STATUS_FILE 2>&1
+       fi
+fi
+
+# Shut down a previously installed server first
+# Note we *could* make that depend on $SERVER_TO_START, but we rather don't,
+# so a "stop" is attempted even if there is no PID file.
+# (Maybe the "stop" doesn't work then, but we might fix that in itself.)
+if [ -x %{_sysconfdir}/init.d/mysql ] ; then
+        %{_sysconfdir}/init.d/mysql stop > /dev/null 2>&1
+        echo "Giving mysqld 5 seconds to exit nicely"
+        sleep 5
+fi
+
+%post -n mysql-wsrep-server%{product_suffix}
+# This is the code running at the end of a RPM install or upgrade action,
+# after the (new) files have been written.
+
+# ATTENTION: Parts of this are duplicated in the "triggerpostun" !
+
+# There are users who deviate from the default file system layout.
+# Check local settings to support them.
+if [ -x %{_bindir}/my_print_defaults ]
+then
+  mysql_datadir=`%{_bindir}/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p'`
+fi
+if [ -z "$mysql_datadir" ]
+then
+  mysql_datadir=%{mysqldatadir}
+fi
+
+NEW_VERSION=%{mysql_version}-%{release}
+STATUS_FILE=$mysql_datadir/RPM_UPGRADE_MARKER
+
+# ----------------------------------------------------------------------
+# Create data directory if needed, check whether upgrade or install
+# ----------------------------------------------------------------------
+if [ ! -d $mysql_datadir ] ; then mkdir -m 755 $mysql_datadir; fi
+if [ -f $STATUS_FILE ] ; then
+       SERVER_TO_START=`grep '^SERVER_TO_START=' $STATUS_FILE | cut -c17-`
+else
+       SERVER_TO_START=''
+fi
+# echo "Analyzed: SERVER_TO_START=$SERVER_TO_START"
+if [ ! -d $mysql_datadir/mysql ] ; then
+       mkdir $mysql_datadir/mysql $mysql_datadir/test
+       echo "MySQL RPM installation of version $NEW_VERSION" >> $STATUS_FILE
+else
+       # If the directory exists, we may assume it is an upgrade.
+       echo "MySQL RPM upgrade to version $NEW_VERSION" >> $STATUS_FILE
+fi
+
+# ----------------------------------------------------------------------
+# Make MySQL start/shutdown automatically when the machine does it.
+# ----------------------------------------------------------------------
+# NOTE: This still needs to be debated. Should we check whether these links
+# for the other run levels exist(ed) before the upgrade?
+# use chkconfig on Enterprise Linux and newer SuSE releases
+if [ -x /sbin/chkconfig ] ; then
+        /sbin/chkconfig --add mysql
+# use insserv for older SuSE Linux versions
+elif [ -x /sbin/insserv ] ; then
+        /sbin/insserv %{_sysconfdir}/init.d/mysql
+fi
+
+# ----------------------------------------------------------------------
+# Create a MySQL user and group. Do not report any problems if it already
+# exists.
+# ----------------------------------------------------------------------
+groupadd -r %{mysqld_group} 2> /dev/null || true
+useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" \
+  -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true
+# The user may already exist, make sure it has the proper group nevertheless
+# (BUG#12823)
+usermod -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true
+
+# ----------------------------------------------------------------------
+# Change permissions so that the user that will run the MySQL daemon
+# owns all database files.
+# ----------------------------------------------------------------------
+chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir
+
+# ----------------------------------------------------------------------
+# Initiate databases if needed
+# ----------------------------------------------------------------------
+if ! grep '^MySQL RPM upgrade' $STATUS_FILE >/dev/null 2>&1 ; then
+       # Fix bug#45415: no "mysql_install_db" on an upgrade
+       # Do this as a negative to err towards more "install" runs
+       # rather than to miss one.
+       %{_bindir}/mysql_install_db --rpm --user=%{mysqld_user} --random-passwords
+
+       # Attention: Now 'root' is the only database user,
+       # its password is a random value found in ~/.mysql_secret,
+       # and the "password expired" flag is set:
+       # Any client needs that password, and the first command
+       # executed must be a new "set password"!
+fi
+
+# ----------------------------------------------------------------------
+# Upgrade databases if needed would go here - but it cannot be automated yet
+# ----------------------------------------------------------------------
+
+# ----------------------------------------------------------------------
+# Change permissions again to fix any new files.
+# ----------------------------------------------------------------------
+chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir
+
+# ----------------------------------------------------------------------
+# Fix permissions for the permission database so that only the user
+# can read them.
+# ----------------------------------------------------------------------
+chmod -R og-rw $mysql_datadir/mysql
+
+# ----------------------------------------------------------------------
+# install SELinux files - but don't override existing ones
+# ----------------------------------------------------------------------
+SETARGETDIR=/etc/selinux/targeted/src/policy
+SEDOMPROG=$SETARGETDIR/domains/program
+SECONPROG=$SETARGETDIR/file_contexts/program
+if [ -f /etc/redhat-release ] \
+ && (grep -q "Red Hat Enterprise Linux .. release 4" /etc/redhat-release \
+ || grep -q "CentOS release 4" /etc/redhat-release) ; then
+  echo
+  echo
+  echo 'Notes regarding SELinux on this platform:'
+  echo '========================================='
+  echo
+  echo 'The default policy might cause server startup to fail because it is'
+  echo 'not allowed to access critical files.  In this case, please update'
+  echo 'your installation.'
+  echo
+  echo 'The default policy might also cause inavailability of SSL related'
+  echo 'features because the server is not allowed to access /dev/random'
+  echo 'and /dev/urandom. If this is a problem, please do the following:'
+  echo
+  echo '  1) install selinux-policy-targeted-sources from your OS vendor'
+  echo '  2) add the following two lines to '$SEDOMPROG/mysqld.te':'
+  echo '       allow mysqld_t random_device_t:chr_file read;'
+  echo '       allow mysqld_t urandom_device_t:chr_file read;'
+  echo '  3) cd to '$SETARGETDIR' and issue the following command:'
+  echo '       make load'
+  echo
+  echo
+fi
+
+if [ -x sbin/restorecon ] ; then
+  sbin/restorecon -R var/lib/mysql
+fi
+
+# Was the server running before the upgrade? If so, restart the new one.
+if [ "$SERVER_TO_START" = "true" ] ; then
+       # Restart in the same way that mysqld will be started normally.
+       if [ -x %{_sysconfdir}/init.d/mysql ] ; then
+               %{_sysconfdir}/init.d/mysql start
+               echo "Giving mysqld 5 seconds to start"
+               sleep 5
+       fi
+fi
+
+# Collect an upgrade history ...
+echo "Upgrade/install finished at `date`"        >> $STATUS_FILE
+echo                                             >> $STATUS_FILE
+echo "====="                                     >> $STATUS_FILE
+STATUS_HISTORY=$mysql_datadir/RPM_UPGRADE_HISTORY
+cat $STATUS_FILE >> $STATUS_HISTORY
+mv -f  $STATUS_FILE ${STATUS_FILE}-LAST  # for "triggerpostun"
+
+
+#echo "Thank you for installing the MySQL Community Server! For Production
+#systems, we recommend MySQL Enterprise, which contains enterprise-ready
+#software, intelligent advisory services, and full production support with
+#scheduled service packs and more.  Visit www.mysql.com/enterprise for more
+#information."
+
+%preun -n mysql-wsrep-server%{product_suffix}
+
+# Which '$1' does this refer to?  Fedora docs have info:
+# " ... a count of the number of versions of the package that are installed.
+#   Action                           Count
+#   Install the first time           1
+#   Upgrade                          2 or higher (depending on the number of versions installed)
+#   Remove last version of package   0 "
+#
+#  http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch09s04s05.html
+
+if [ $1 = 0 ] ; then
+        # Stop MySQL before uninstalling it
+        if [ -x %{_sysconfdir}/init.d/mysql ] ; then
+                %{_sysconfdir}/init.d/mysql stop > /dev/null
+                # Remove autostart of MySQL
+                # use chkconfig on Enterprise Linux and newer SuSE releases
+                if [ -x /sbin/chkconfig ] ; then
+                        /sbin/chkconfig --del mysql
+                # For older SuSE Linux versions
+                elif [ -x /sbin/insserv ] ; then
+                        /sbin/insserv -r %{_sysconfdir}/init.d/mysql
+                fi
+        fi
+fi
+
+# We do not remove the mysql user since it may still own a lot of
+# database files.
+
+%triggerpostun -n mysql-wsrep-server%{product_suffix} --MySQL-server-community
+
+# Setup: We renamed this package, so any existing "server-community"
+#   package will be removed when this "server" is installed.
+# Problem: RPM will first run the "pre" and "post" sections of this script,
+#   and only then the "preun" of that old community server.
+#   But this "preun" includes stopping the server and uninstalling the service,
+#   "chkconfig --del mysql" which removes the symlinks to the start script.
+# Solution: *After* the community server got removed, restart this server
+#   and re-install the service.
+#
+# For information about triggers in spec files, see the Fedora docs:
+#   http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch10s02.html
+# For all details of this code, see the "pre" and "post" sections.
+
+# There are users who deviate from the default file system layout.
+# Check local settings to support them.
+if [ -x %{_bindir}/my_print_defaults ]
+then
+  mysql_datadir=`%{_bindir}/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p'`
+fi
+if [ -z "$mysql_datadir" ]
+then
+  mysql_datadir=%{mysqldatadir}
+fi
+
+NEW_VERSION=%{mysql_version}-%{release}
+STATUS_FILE=$mysql_datadir/RPM_UPGRADE_MARKER-LAST  # Note the difference!
+STATUS_HISTORY=$mysql_datadir/RPM_UPGRADE_HISTORY
+
+if [ -f $STATUS_FILE ] ; then
+       SERVER_TO_START=`grep '^SERVER_TO_START=' $STATUS_FILE | cut -c17-`
+else
+       # This should never happen, but let's be prepared
+       SERVER_TO_START=''
+fi
+echo "Analyzed: SERVER_TO_START=$SERVER_TO_START"
+
+if [ -x /sbin/chkconfig ] ; then
+        /sbin/chkconfig --add mysql
+# use insserv for older SuSE Linux versions
+elif [ -x /sbin/insserv ] ; then
+        /sbin/insserv %{_sysconfdir}/init.d/mysql
+fi
+
+# Was the server running before the upgrade? If so, restart the new one.
+if [ "$SERVER_TO_START" = "true" ] ; then
+       # Restart in the same way that mysqld will be started normally.
+       if [ -x %{_sysconfdir}/init.d/mysql ] ; then
+               %{_sysconfdir}/init.d/mysql start
+               echo "Giving mysqld 5 seconds to start"
+               sleep 5
+       fi
+fi
+
+echo "Trigger 'postun --community' finished at `date`"        >> $STATUS_HISTORY
+echo                                             >> $STATUS_HISTORY
+echo "====="                                     >> $STATUS_HISTORY
+
+
+# ----------------------------------------------------------------------
+# Clean up the BuildRoot after build is done
+# ----------------------------------------------------------------------
+%clean
+[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] \
+  && rm -rf $RPM_BUILD_ROOT;
+
+##############################################################################
+#  Files section
+##############################################################################
+
+%files -n mysql-wsrep%{product_suffix}
+# Intentionally empty - this is a pure meta package.
+
+# ----------------------------------------------------------------------------
+%files -n mysql-wsrep-server%{product_suffix} -f release/support-files/plugins.files
+%defattr(-,root,root,0755)
+%if %{defined license_files_server}
+%doc %{license_files_server}
+%endif
+%doc Docs/ChangeLog
+%doc release/Docs/INFO_SRC*
+%doc release/Docs/INFO_BIN*
+%doc release/support-files/my-default.cnf
+%doc Docs/README-wsrep
+%doc release/support-files/wsrep.cnf
+%doc release/support-files/wsrep_notify
+
+%if 0%{?commercial}
+%doc %attr(644, root, root) %{_infodir}/mysql.info*
+%endif
+
+%doc %attr(644, root, man) %{_mandir}/man1/innochecksum.1*
+%doc %attr(644, root, man) %{_mandir}/man1/my_print_defaults.1*
+%doc %attr(644, root, man) %{_mandir}/man1/myisam_ftdump.1*
+%doc %attr(644, root, man) %{_mandir}/man1/myisamchk.1*
+%doc %attr(644, root, man) %{_mandir}/man1/myisamlog.1*
+%doc %attr(644, root, man) %{_mandir}/man1/myisampack.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_convert_table_format.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_fix_extensions.1*
+%doc %attr(644, root, man) %{_mandir}/man8/mysqld.8*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqld_multi.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqld_safe.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqldumpslow.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_install_db.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_plugin.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_secure_installation.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_setpermission.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_upgrade.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlhotcopy.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlman.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql.server.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqltest.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_tzinfo_to_sql.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_zap.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlbug.1*
+%doc %attr(644, root, man) %{_mandir}/man1/perror.1*
+%doc %attr(644, root, man) %{_mandir}/man1/replace.1*
+%doc %attr(644, root, man) %{_mandir}/man1/resolve_stack_dump.1*
+%doc %attr(644, root, man) %{_mandir}/man1/resolveip.1*
+
+%ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf
+%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf
+%dir %{_sysconfdir}/my.cnf.d
+
+%attr(755, root, root) %{_bindir}/innochecksum
+%attr(755, root, root) %{_bindir}/my_print_defaults
+%attr(755, root, root) %{_bindir}/myisam_ftdump
+%attr(755, root, root) %{_bindir}/myisamchk
+%attr(755, root, root) %{_bindir}/myisamlog
+%attr(755, root, root) %{_bindir}/myisampack
+%attr(755, root, root) %{_bindir}/mysql_convert_table_format
+%attr(755, root, root) %{_bindir}/mysql_fix_extensions
+%attr(755, root, root) %{_bindir}/mysql_install_db
+%attr(755, root, root) %{_bindir}/mysql_plugin
+%attr(755, root, root) %{_bindir}/mysql_secure_installation
+%attr(755, root, root) %{_bindir}/mysql_setpermission
+%attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql
+%attr(755, root, root) %{_bindir}/mysql_upgrade
+%attr(755, root, root) %{_bindir}/mysql_zap
+%attr(755, root, root) %{_bindir}/mysqlbug
+%attr(755, root, root) %{_bindir}/mysqld_multi
+%attr(755, root, root) %{_bindir}/mysqld_safe
+%attr(755, root, root) %{_bindir}/mysqldumpslow
+%attr(755, root, root) %{_bindir}/mysqlhotcopy
+%attr(755, root, root) %{_bindir}/mysqltest
+%attr(755, root, root) %{_bindir}/perror
+%attr(755, root, root) %{_bindir}/replace
+%attr(755, root, root) %{_bindir}/resolve_stack_dump
+%attr(755, root, root) %{_bindir}/resolveip
+%attr(755, root, root) %{_bindir}/wsrep_sst_common
+%attr(755, root, root) %{_bindir}/wsrep_sst_mysqldump
+%attr(755, root, root) %{_bindir}/wsrep_sst_rsync
+%attr(755, root, root) %{_bindir}/wsrep_sst_rsync_wan
+%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup
+%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup-v2
+
+%attr(755, root, root) %{_sbindir}/mysqld
+%attr(755, root, root) %{_sbindir}/mysqld-debug
+%attr(755, root, root) %{_sbindir}/rcmysql
+%dir %{_libdir}/mysql/plugin
+%dir %{_libdir}/mysql/plugin/debug
+%attr(755, root, root) %{_libdir}/mysql/plugin/daemon_example.ini
+
+%if %{WITH_TCMALLOC}
+%attr(755, root, root) %{_libdir}/mysql/%{malloc_lib_target}
+%endif
+
+%attr(644, root, root) %config(noreplace,missingok) %{_sysconfdir}/logrotate.d/mysql
+%attr(755, root, root) %{_sysconfdir}/init.d/mysql
+%attr(755, root, root) %{_datadir}/mysql/
+%dir %attr(755, mysql, mysql) /var/lib/mysql
+
+# ----------------------------------------------------------------------------
+%files -n mysql-wsrep-client%{product_suffix}
+
+%defattr(-, root, root, 0755)
+%if %{defined license_files_server}
+%doc %{license_files_server}
+%endif
+%attr(755, root, root) %{_bindir}/msql2mysql
+%attr(755, root, root) %{_bindir}/mysql
+%attr(755, root, root) %{_bindir}/mysql_find_rows
+%attr(755, root, root) %{_bindir}/mysql_waitpid
+%attr(755, root, root) %{_bindir}/mysqlaccess
+# XXX: This should be moved to %{_sysconfdir}
+%attr(644, root, root) %{_bindir}/mysqlaccess.conf
+%attr(755, root, root) %{_bindir}/mysqladmin
+%attr(755, root, root) %{_bindir}/mysqlbinlog
+%attr(755, root, root) %{_bindir}/mysqlcheck
+%attr(755, root, root) %{_bindir}/mysqldump
+%attr(755, root, root) %{_bindir}/mysqlimport
+%attr(755, root, root) %{_bindir}/mysqlshow
+%attr(755, root, root) %{_bindir}/mysqlslap
+%attr(755, root, root) %{_bindir}/mysql_config_editor
+
+%doc %attr(644, root, man) %{_mandir}/man1/msql2mysql.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_find_rows.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_waitpid.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlaccess.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqladmin.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlbinlog.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlcheck.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqldump.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlimport.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlshow.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqlslap.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_config_editor.1*
+
+# ----------------------------------------------------------------------------
+%files -n mysql-wsrep-devel%{product_suffix} -f optional-files-devel
+%defattr(-, root, root, 0755)
+%if %{defined license_files_server}
+%doc %{license_files_server}
+%endif
+%doc %attr(644, root, man) %{_mandir}/man1/comp_err.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_config.1*
+%attr(755, root, root) %{_bindir}/mysql_config
+%dir %attr(755, root, root) %{_includedir}/mysql
+%dir %attr(755, root, root) %{_libdir}/mysql
+%{_includedir}/mysql/*
+%{_datadir}/aclocal/mysql.m4
+%{_libdir}/mysql/libmysqlclient.a
+%{_libdir}/mysql/libmysqlclient_r.a
+%{_libdir}/mysql/libmysqlservices.a
+
+# ----------------------------------------------------------------------------
+%files -n mysql-wsrep-shared%{product_suffix}
+%defattr(-, root, root, 0755)
+%if %{defined license_files_server}
+%doc %{license_files_server}
+%endif
+# Shared libraries (omit for architectures that don't support them)
+%{_libdir}/libmysql*.so*
+
+%post -n mysql-wsrep-shared%{product_suffix}
+/sbin/ldconfig
+
+%postun -n mysql-wsrep-shared%{product_suffix}
+/sbin/ldconfig
+
+# ----------------------------------------------------------------------------
+%files -n mysql-wsrep-test%{product_suffix}
+%defattr(-, root, root, 0755)
+%if %{defined license_files_server}
+%doc %{license_files_server}
+%endif
+%attr(-, root, root) %{_datadir}/mysql-test
+%attr(755, root, root) %{_bindir}/mysql_client_test
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql-stress-test.pl.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql-test-run.pl.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test_embedded.1*
+%doc %attr(644, root, man) %{_mandir}/man1/mysqltest_embedded.1*
+
+##############################################################################
+# The spec file changelog only includes changes made to the spec file
+# itself - note that they must be ordered by date (important when
+# merging BK trees)
+##############################################################################
+%changelog
+* Thu Sep 24 2015 Ivan Suzdal <isuzdal@mirantis.com> - 5.6.23-25.10%{?dist}~mos8.0.1
+- Bump release version
+
+* Thu Jan 29 2015 Joerg Bruehe <joerg.bruehe@fromdual.com>
+- Add a meta-package "mysql-wsrep" that requires both "server" and "client".
+- Fix the fall-back definition of "dist", it must start with a period.
+
+* Mon Jan 26 2015 Joerg Bruehe <joerg.bruehe@fromdual.com>
+- Allow "rpmlint", but suppress "post-build-checks" (fail on SuSE 12 + 13).
+- Improve handling of undefined "%%{dist}".
+- Fix wrong changelog dates, to get rid of warnings about "bogus date".
+- Escape percent signs in changelog, to get rid of "rpmlint" warnings.
+
+* Tue Jan 20 2015 Teemu Ollakka <teemu.ollakka@galeracluster.com>
+
+- Reworked to build wsrep patched packages exclusively
+- OBS compatible
+
+* Mon Oct 06 2014 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Add license info in each subpackage
+
+* Wed May 28 2014 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Updated usergroup to mysql on datadir
+
+* Wed Oct 30 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Removed non gpl file docs/mysql.info from community packages
+
+* Mon Sep 09 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Updated logic to get the correct count of PID files
+
+* Fri Aug 16 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Added provides lowercase mysql tags
+
+* Wed Jun 26 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
+- Cleaned up spec file to resolve rpm dependencies.
+
+* Mon Nov 05 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Allow to override the default to use the bundled yaSSL by an option like
+      --define="with_ssl /path/to/ssl"
+
+* Wed Oct 10 2012 Bjorn Munch <bjorn.munch@oracle.com>
+
+- Replace old my-*.cnf config file examples with template my-default.cnf
+
+* Fri Oct 05 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Let the installation use the new option "--random-passwords" of "mysql_install_db".
+  (Bug# 12794345 Ensure root password)
+- Fix an inconsistency: "new install" vs "upgrade" are told from the (non)existence
+  of "$mysql_datadir/mysql" (holding table "mysql.user" and other system stuff).
+
+* Tue Jul 24 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Add a macro "runselftest":
+  if set to 1 (default), the test suite will be run during the RPM build;
+  this can be oveeridden via the command line by adding
+      --define "runselftest 0"
+  Failures of the test suite will NOT make the RPM build fail!
+
+* Mon Jul 16 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Add the man page for the "mysql_config_editor".
+
+* Mon Jun 11 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Make sure newly added "SPECIFIC-ULN/" directory does not disturb packaging.
+
+* Wed Feb 29 2012 Brajmohan Saxena <brajmohan.saxena@oracle.com>
+
+- Removal all traces of the readline library from mysql (BUG 13738013)
+
+* Wed Sep 28 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Fix duplicate mentioning of "mysql_plugin" and its manual page,
+  it is better to keep alphabetic order in the files list (merging!).
+
+* Wed Sep 14 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Let the RPM capabilities ("obsoletes" etc) ensure that an upgrade may replace
+  the RPMs of any configuration (of the current or the preceding release series)
+  by the new ones. This is done by not using the implicitly generated capabilities
+  (which include the configuration name) and relying on more generic ones which
+  just list the function ("server", "client", ...).
+  The implicit generation cannot be prevented, so all these capabilities must be
+  explicitly listed in "Obsoletes:"
+
+* Tue Sep 13 2011 Jonathan Perkin <jonathan.perkin@oracle.com>
+
+- Add support for Oracle Linux 6 and Red Hat Enterprise Linux 6.  Due to
+  changes in RPM behaviour ($RPM_BUILD_ROOT is removed prior to install)
+  this necessitated a move of the libmygcc.a installation to the install
+  phase, which is probably where it belonged in the first place.
+
+* Tue Sep 13 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- "make_win_bin_dist" and its manual are dropped, cmake does it different.
+
+* Thu Sep 08 2011 Daniel Fischer <daniel.fischer@oracle.com>
+
+- Add mysql_plugin man page.
+
+* Tue Aug 30 2011 Tor Didriksen <tor.didriksen@oracle.com>
+
+- Set CXX=g++ by default to add a dependency on libgcc/libstdc++.
+  Also, remove the use of the -fno-exceptions and -fno-rtti flags.
+  TODO: update distro_buildreq/distro_requires
+
+* Tue Aug 30 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Add the manual page for "mysql_plugin" to the server package.
+
+* Fri Aug 19 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Null-upmerge the fix of bug#37165: This spec file is not affected.
+- Replace "/var/lib/mysql" by the spec file variable "%%{mysqldatadir}".
+
+* Fri Aug 12 2011 Daniel Fischer <daniel.fischer@oracle.com>
+
+- Source plugin library files list from cmake-generated file.
+
+* Mon Jul 25 2011 Chuck Bell <chuck.bell@oracle.com>
+
+- Added the mysql_plugin client - enables or disables plugins.
+
+* Thu Jul 21 2011 Sunanda Menon <sunanda.menon@oracle.com>
+
+- Fix bug#12561297: Added the MySQL embedded binary
+
+* Thu Jul 07 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Fix bug#45415: "rpm upgrade recreates test database"
+  Let the creation of the "test" database happen only during a new installation,
+  not in an RPM upgrade.
+  This affects both the "mkdir" and the call of "mysql_install_db".
+
+* Thu Feb 10 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Fix bug#56581: If an installation deviates from the default file locations
+  ("datadir" and "pid-file"), the mechanism to detect a running server (on upgrade)
+  should still work, and use these locations.
+  The problem was that the fix for bug#27072 did not check for local settings.
+
+* Mon Jan 31 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- Install the new "manifest" files: "INFO_SRC" and "INFO_BIN".
+
+* Tue Nov 23 2010 Jonathan Perkin <jonathan.perkin@oracle.com>
+
+- EXCEPTIONS-CLIENT has been deleted, remove it from here too
+- Support MYSQL_BUILD_MAKE_JFLAG environment variable for passing
+  a '-j' argument to make.
+
+* Mon Nov 1 2010 Georgi Kodinov <georgi.godinov@oracle.com>
+
+- Added test authentication (WL#1054) plugin binaries
+
+* Wed Oct 6 2010 Georgi Kodinov <georgi.godinov@oracle.com>
+
+- Added example external authentication (WL#1054) plugin binaries
+
+* Wed Aug 11 2010 Joerg Bruehe <joerg.bruehe@oracle.com>
+
+- With a recent spec file cleanup, names have changed: A "-community" part was dropped.
+  Reflect that in the "Obsoletes" specifications.
+- Add a "triggerpostun" to handle the uninstall of the "-community" server RPM.
+- This fixes bug#55015 "MySQL server is not restarted properly after RPM upgrade".
+
+* Tue Jun 15 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Change the behaviour on installation and upgrade:
+  On installation, do not autostart the server.
+  *Iff* the server was stopped before the upgrade is started, this is taken as a
+  sign the administrator is handling that manually, and so the new server will
+  not be started automatically at the end of the upgrade.
+  The start/stop scripts will still be installed, so the server will be started
+  on the next machine boot.
+  This is the 5.5 version of fixing bug#27072 (RPM autostarting the server).
+
+* Tue Jun 1 2010 Jonathan Perkin <jonathan.perkin@oracle.com>
+
+- Implement SELinux checks from distribution-specific spec file.
+
+* Wed May 12 2010 Jonathan Perkin <jonathan.perkin@oracle.com>
+
+- Large number of changes to build using CMake
+- Introduce distribution-specific RPMs
+- Drop debuginfo, build all binaries with debug/symbols
+- Remove __os_install_post, use native macro
+- Remove _unpackaged_files_terminate_build, make it an error to have
+  unpackaged files
+- Remove cluster RPMs
+
+* Wed Mar 24 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Add "--with-perfschema" to the configure options.
+
+* Mon Mar 22 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- User "usr/lib*" to allow for both "usr/lib" and "usr/lib64",
+  mask "rmdir" return code 1.
+- Remove "ha_example.*" files from the list, they aren't built.
+
+* Wed Mar 17 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Fix a wrong path name in handling the debug plugins.
+
+* Wed Mar 10 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Take the result of the debug plugin build and put it into the optimized tree,
+  so that it becomes part of the final installation;
+  include the files in the packlist. Part of the fixes for bug#49022.
+
+* Mon Mar 01 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Set "Oracle and/or its affiliates" as the vendor and copyright owner,
+  accept upgrading from packages showing MySQL or Sun as vendor.
+
+* Fri Feb 12 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Formatting changes:
+  Have a consistent structure of separator lines and of indentation
+  (8 leading blanks => tab).
+- Introduce the variable "src_dir".
+- Give the environment variables "MYSQL_BUILD_CC(CXX)" precedence
+  over "CC" ("CXX").
+- Drop the old "with_static" argument analysis, this is not supported
+  in 5.1 since ages.
+- Introduce variables to control the handlers individually, as well
+  as other options.
+- Use the new "--with-plugin" notation for the table handlers.
+- Drop handling "/etc/rc.d/init.d/mysql", the switch to "/etc/init.d/mysql"
+  was done back in 2002 already.
+- Make "--with-zlib-dir=bundled" the default, add an option to disable it.
+- Add missing manual pages to the file list.
+- Improve the runtime check for "libgcc.a", protect it against being tried
+  with the Intel compiler "icc".
+
+* Mon Jan 11 2010 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Change RPM file naming:
+  - Suffix like "-m2", "-rc" becomes part of version as "_m2", "_rc".
+  - Release counts from 1, not 0.
+
+* Wed Dec 23 2009 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- The "semisync" plugin file name has lost its introductory "lib",
+  adapt the file lists for the subpackages.
+  This is a part missing from the fix for bug#48351.
+- Remove the "fix_privilege_tables" manual, it does not exist in 5.5
+  (and likely, the whole script will go, too).
+
+* Mon Nov 16 2009 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Fix some problems with the directives around "tcmalloc" (experimental),
+  remove erroneous traces of the InnoDB plugin (that is 5.1 only).
+
+* Fri Oct 09 2009 Magnus Blaudd <mvensson@mysql.com>
+
+- Removed mysql_fix_privilege_tables
+
+* Fri Oct 02 2009 Alexander Nozdrin <alexander.nozdrin@sun.com>
+
+- "mysqlmanager" got removed from version 5.4, all references deleted.
+
+* Fri Aug 28 2009 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- Merge up from 5.1 to 5.4: Remove handling for the InnoDB plugin.
+
+* Thu Aug 27 2009 Joerg Bruehe <joerg.bruehe@sun.com>
+
+- This version does not contain the "Instance manager", "mysqlmanager":
+  Remove it from the spec file so that packaging succeeds.
+
+* Mon Aug 24 2009 Jonathan Perkin <jperkin@sun.com>
+
+- Add conditionals for bundled zlib and innodb plugin
+
+* Fri Aug 21 2009 Jonathan Perkin <jperkin@sun.com>
+
+- Install plugin libraries in appropriate packages.
+- Disable libdaemon_example and ftexample plugins.
+
+* Thu Aug 20 2009 Jonathan Perkin <jperkin@sun.com>
+
+- Update variable used for mysql-test suite location to match source.
+
+* Fri Nov 07 2008 Joerg Bruehe <joerg@mysql.com>
+
+- Correct yesterday's fix, so that it also works for the last flag,
+  and fix a wrong quoting: un-quoted quote marks must not be escaped.
+
+* Thu Nov 06 2008 Kent Boortz <kent.boortz@sun.com>
+
+- Removed "mysql_upgrade_shell"
+- Removed some copy/paste between debug and normal build
+
+* Thu Nov 06 2008 Joerg Bruehe <joerg@mysql.com>
+
+- Modify CFLAGS and CXXFLAGS such that a debug build is not optimized.
+  This should cover both gcc and icc flags.  Fixes bug#40546.
+
+* Fri Aug 29 2008 Kent Boortz <kent@mysql.com>
+
+- Removed the "Federated" storage engine option, and enabled in all
+
+* Tue Aug 26 2008 Joerg Bruehe <joerg@mysql.com>
+
+- Get rid of the "warning: Installed (but unpackaged) file(s) found:"
+  Some generated files aren't needed in RPMs:
+  - the "sql-bench/" subdirectory
+  Some files were missing:
+  - /usr/share/aclocal/mysql.m4  ("devel" subpackage)
+  - Manual "mysqlbug" ("server" subpackage)
+  - Program "innochecksum" and its manual ("server" subpackage)
+  - Manual "mysql_find_rows" ("client" subpackage)
+  - Script "mysql_upgrade_shell" ("client" subpackage)
+  - Program "ndb_cpcd" and its manual ("ndb-extra" subpackage)
+  - Manuals "ndb_mgm" + "ndb_restore" ("ndb-tools" subpackage)
+
+* Mon Mar 31 2008 Kent Boortz <kent@mysql.com>
+
+- Made the "Federated" storage engine an option
+- Made the "Cluster" storage engine and sub packages an option
+
+* Wed Mar 19 2008 Joerg Bruehe <joerg@mysql.com>
+
+- Add the man pages for "ndbd" and "ndb_mgmd".
+
+* Mon Feb 18 2008 Timothy Smith <tim@mysql.com>
+
+- Require a manual upgrade if the alread-installed mysql-server is
+  from another vendor, or is of a different major version.
+
+* Wed May 02 2007 Joerg Bruehe <joerg@mysql.com>
+
+- "ndb_size.tmpl" is not needed any more,
+  "man1/mysql_install_db.1" lacked the trailing '*'.
+
+* Sat Apr 07 2007 Kent Boortz <kent@mysql.com>
+
+- Removed man page for "mysql_create_system_tables"
+
+* Wed Mar 21 2007 Daniel Fischer <df@mysql.com>
+
+- Add debug server.
+
+* Mon Mar 19 2007 Daniel Fischer <df@mysql.com>
+
+- Remove Max RPMs; the server RPMs contain a mysqld compiled with all
+  features that previously only were built into Max.
+
+* Fri Mar 02 2007 Joerg Bruehe <joerg@mysql.com>
+
+- Add several man pages for NDB which are now created.
+
+* Fri Jan 05 2007 Kent Boortz <kent@mysql.com>
+
+- Put back "libmygcc.a", found no real reason it was removed.
+
+- Add CFLAGS to gcc call with --print-libgcc-file, to make sure the
+  correct "libgcc.a" path is returned for the 32/64 bit architecture.
+
+* Mon Dec 18 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Fix the move of "mysqlmanager" to section 8: Directory name was wrong.
+
+* Thu Dec 14 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Include the new man pages for "my_print_defaults" and "mysql_tzinfo_to_sql"
+  in the server RPM.
+- The "mysqlmanager" man page got moved from section 1 to 8.
+
+* Thu Nov 30 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Call "make install" using "benchdir_root=%%{_datadir}",
+  because that is affecting the regression test suite as well.
+
+* Thu Nov 16 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Explicitly note that the "MySQL-shared" RPMs (as built by MySQL AB)
+  replace "mysql-shared" (as distributed by SuSE) to allow easy upgrading
+  (bug#22081).
+
+* Mon Nov 13 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Add "--with-partition" to all server builds.
+
+- Use "--report-features" in one test run per server build.
+
+* Tue Aug 15 2006 Joerg Bruehe <joerg@mysql.com>
+
+- The "max" server is removed from packages, effective from 5.1.12-beta.
+  Delete all steps to build, package, or install it.
+
+* Mon Jul 10 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Fix a typing error in the "make" target for the Perl script to run the tests.
+
+* Tue Jul 04 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Use the Perl script to run the tests, because it will automatically check
+  whether the server is configured with SSL.
+
+* Tue Jun 27 2006 Joerg Bruehe <joerg@mysql.com>
+
+- move "mysqldumpslow" from the client RPM to the server RPM (bug#20216)
+
+- Revert all previous attempts to call "mysql_upgrade" during RPM upgrade,
+  there are some more aspects which need to be solved before this is possible.
+  For now, just ensure the binary "mysql_upgrade" is delivered and installed.
+
+* Thu Jun 22 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Close a gap of the previous version by explicitly using
+  a newly created temporary directory for the socket to be used
+  in the "mysql_upgrade" operation, overriding any local setting.
+
+* Tue Jun 20 2006 Joerg Bruehe <joerg@mysql.com>
+
+- To run "mysql_upgrade", we need a running server;
+  start it in isolation and skip password checks.
+
+* Sat May 20 2006 Kent Boortz <kent@mysql.com>
+
+- Always compile for PIC, position independent code.
+
+* Wed May 10 2006 Kent Boortz <kent@mysql.com>
+
+- Use character set "all" when compiling with Cluster, to make Cluster
+  nodes independent on the character set directory, and the problem
+  that two RPM sub packages both wants to install this directory.
+
+* Mon May 01 2006 Kent Boortz <kent@mysql.com>
+
+- Use "./libtool --mode=execute" instead of searching for the
+  executable in current directory and ".libs".
+
+* Fri Apr 28 2006 Kent Boortz <kent@mysql.com>
+
+- Install and run "mysql_upgrade"
+
+* Wed Apr 12 2006 Jim Winstead <jimw@mysql.com>
+
+- Remove sql-bench, and MySQL-bench RPM (will be built as an independent
+  project from the mysql-bench repository)
+
+* Tue Apr 11 2006 Jim Winstead <jimw@mysql.com>
+
+- Remove old mysqltestmanager and related programs
+* Sat Apr 01 2006 Kent Boortz <kent@mysql.com>
+
+- Set $LDFLAGS from $MYSQL_BUILD_LDFLAGS
+
+* Wed Mar 08 2006 Kent Boortz <kent@mysql.com>
+
+- Changed product name from "Community Edition" to "Community Server"
+
+* Mon Mar 06 2006 Kent Boortz <kent@mysql.com>
+
+- Fast mutexes is now disabled by default, but should be
+  used in Linux builds.
+
+* Mon Feb 20 2006 Kent Boortz <kent@mysql.com>
+
+- Reintroduced a max build
+- Limited testing of 'debug' and 'max' servers
+- Berkeley DB only in 'max'
+
+* Mon Feb 13 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Use "-i" on "make test-force";
+  this is essential for later evaluation of this log file.
+
+* Thu Feb 09 2006 Kent Boortz <kent@mysql.com>
+
+- Pass '-static' to libtool, link static with our own libraries, dynamic
+  with system libraries.  Link with the bundled zlib.
+
+* Wed Feb 08 2006 Kristian Nielsen <knielsen@mysql.com>
+
+- Modified RPM spec to match new 5.1 debug+max combined community packaging.
+
+* Sun Dec 18 2005 Kent Boortz <kent@mysql.com>
+
+- Added "client/mysqlslap"
+
+* Mon Dec 12 2005 Rodrigo Novo <rodrigo@mysql.com>
+
+- Added zlib to the list of (static) libraries installed
+- Added check against libtool wierdness (WRT: sql/mysqld || sql/.libs/mysqld)
+- Compile MySQL with bundled zlib
+- Fixed %%packager name to "MySQL Production Engineering Team"
+
+* Mon Dec 05 2005 Joerg Bruehe <joerg@mysql.com>
+
+- Avoid using the "bundled" zlib on "shared" builds:
+  As it is not installed (on the build system), this gives dependency
+  problems with "libtool" causing the build to fail.
+  (Change was done on Nov 11, but left uncommented.)
+
+* Tue Nov 22 2005 Joerg Bruehe <joerg@mysql.com>
+
+- Extend the file existence check for "init.d/mysql" on un-install
+  to also guard the call to "insserv"/"chkconfig".
+
+* Thu Oct 27 2005 Lenz Grimmer <lenz@grimmer.com>
+
+- added more man pages
+
+* Wed Oct 19 2005 Kent Boortz <kent@mysql.com>
+
+- Made yaSSL support an option (off by default)
+
+* Wed Oct 19 2005 Kent Boortz <kent@mysql.com>
+
+- Enabled yaSSL support
+
+* Sat Oct 15 2005 Kent Boortz <kent@mysql.com>
+
+- Give mode arguments the same way in all places
+- Moved copy of mysqld.a to "standard" build, but
+  disabled it as we don't do embedded yet in 5.0
+
+* Fri Oct 14 2005 Kent Boortz <kent@mysql.com>
+
+- For 5.x, always compile with --with-big-tables
+- Copy the config.log file to location outside
+  the build tree
+
+* Fri Oct 14 2005 Kent Boortz <kent@mysql.com>
+
+- Removed unneeded/obsolete configure options
+- Added archive engine to standard server
+- Removed the embedded server from experimental server
+- Changed suffix "-Max" => "-max"
+- Changed comment string "Max" => "Experimental"
+
+* Thu Oct 13 2005 Lenz Grimmer <lenz@mysql.com>
+
+- added a usermod call to assign a potential existing mysql user to the
+  correct user group (BUG#12823)
+- Save the perror binary built during Max build so it supports the NDB
+  error codes (BUG#13740)
+- added a separate macro "mysqld_group" to be able to define the
+  user group of the mysql user seperately, if desired.
+
+* Thu Sep 29 2005 Lenz Grimmer <lenz@mysql.com>
+
+- fixed the removing of the RPM_BUILD_ROOT in the %%clean section (the
+  $RBR variable did not get expanded, thus leaving old build roots behind)
+
+* Thu Aug 04 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Fixed the creation of the mysql user group account in the postinstall
+  section (BUG 12348)
+- Fixed enabling the Archive storage engine in the Max binary
+
+* Tue Aug 02 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Fixed the Requires: tag for the server RPM (BUG 12233)
+
+* Fri Jul 15 2005 Lenz Grimmer <lenz@mysql.com>
+
+- create a "mysql" user group and assign the mysql user account to that group
+  in the server postinstall section. (BUG 10984)
+
+* Tue Jun 14 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Do not build statically on i386 by default, only when adding either "--with
+  static" or "--define '_with_static 1'" to the RPM build options. Static
+  linking really only makes sense when linking against the specially patched
+  glibc 2.2.5.
+
+* Mon Jun 06 2005 Lenz Grimmer <lenz@mysql.com>
+
+- added mysql_client_test to the "bench" subpackage (BUG 10676)
+- added the libndbclient static and shared libraries (BUG 10676)
+
+* Wed Jun 01 2005 Lenz Grimmer <lenz@mysql.com>
+
+- use "mysqldatadir" variable instead of hard-coding the path multiple times
+- use the "mysqld_user" variable on all occasions a user name is referenced
+- removed (incomplete) Brazilian translations
+- removed redundant release tags from the subpackage descriptions
+
+* Wed May 25 2005 Joerg Bruehe <joerg@mysql.com>
+
+- Added a "make clean" between separate calls to "BuildMySQL".
+
+* Thu May 12 2005 Guilhem Bichot <guilhem@mysql.com>
+
+- Removed the mysql_tableinfo script made obsolete by the information schema
+
+* Wed Apr 20 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Enabled the "blackhole" storage engine for the Max RPM
+
+* Wed Apr 13 2005 Lenz Grimmer <lenz@mysql.com>
+
+- removed the MySQL manual files (html/ps/texi) - they have been removed
+  from the MySQL sources and are now available seperately.
+
+* Mon Apr 4 2005 Petr Chardin <petr@mysql.com>
+
+- old mysqlmanager, mysqlmanagerc and mysqlmanager-pwger renamed into
+  mysqltestmanager, mysqltestmanager and mysqltestmanager-pwgen respectively
+
+* Fri Mar 18 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Disabled RAID in the Max binaries once and for all (it has finally been
+  removed from the source tree)
+
+* Sun Feb 20 2005 Petr Chardin <petr@mysql.com>
+
+- Install MySQL Instance Manager together with mysqld, touch mysqlmanager
+  password file
+
+* Mon Feb 14 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Fixed the compilation comments and moved them into the separate build sections
+  for Max and Standard
+
+* Mon Feb 7 2005 Tomas Ulin <tomas@mysql.com>
+
+- enabled the "Ndbcluster" storage engine for the max binary
+- added extra make install in ndb subdir after Max build to get ndb binaries
+- added packages for ndbcluster storage engine
+
+* Fri Jan 14 2005 Lenz Grimmer <lenz@mysql.com>
+
+- replaced obsoleted "BuildPrereq" with "BuildRequires" instead
+
+* Thu Jan 13 2005 Lenz Grimmer <lenz@mysql.com>
+
+- enabled the "Federated" storage engine for the max binary
+
+* Tue Jan 04 2005 Petr Chardin <petr@mysql.com>
+
+- ISAM and merge storage engines were purged. As well as appropriate
+  tools and manpages (isamchk and isamlog)
+
+* Fri Dec 31 2004 Lenz Grimmer <lenz@mysql.com>
+
+- enabled the "Archive" storage engine for the max binary
+- enabled the "CSV" storage engine for the max binary
+- enabled the "Example" storage engine for the max binary
+
+* Thu Aug 26 2004 Lenz Grimmer <lenz@mysql.com>
+
+- MySQL-Max now requires MySQL-server instead of MySQL (BUG 3860)
+
+* Fri Aug 20 2004 Lenz Grimmer <lenz@mysql.com>
+
+- do not link statically on IA64/AMD64 as these systems do not have
+  a patched glibc installed
+
+* Tue Aug 10 2004 Lenz Grimmer <lenz@mysql.com>
+
+- Added libmygcc.a to the devel subpackage (required to link applications
+  against the the embedded server libmysqld.a) (BUG 4921)
+
+* Mon Aug 09 2004 Lenz Grimmer <lenz@mysql.com>
+
+- Added EXCEPTIONS-CLIENT to the "devel" package
+
+* Thu Jul 29 2004 Lenz Grimmer <lenz@mysql.com>
+
+- disabled OpenSSL in the Max binaries again (the RPM packages were the
+  only exception to this anyway) (BUG 1043)
+
+* Wed Jun 30 2004 Lenz Grimmer <lenz@mysql.com>
+
+- fixed server postinstall (mysql_install_db was called with the wrong
+  parameter)
+
+* Thu Jun 24 2004 Lenz Grimmer <lenz@mysql.com>
+
+- added mysql_tzinfo_to_sql to the server subpackage
+- run "make clean" instead of "make distclean"
+
+* Mon Apr 05 2004 Lenz Grimmer <lenz@mysql.com>
+
+- added ncurses-devel to the build prerequisites (BUG 3377)
+
+* Thu Feb 12 2004 Lenz Grimmer <lenz@mysql.com>
+
+- when using gcc, _always_ use CXX=gcc
+- replaced Copyright with License field (Copyright is obsolete)
+
+* Tue Feb 03 2004 Lenz Grimmer <lenz@mysql.com>
+
+- added myisam_ftdump to the Server package
+
+* Tue Jan 13 2004 Lenz Grimmer <lenz@mysql.com>
+
+- link the mysql client against libreadline instead of libedit (BUG 2289)
+
+* Mon Dec 22 2003 Lenz Grimmer <lenz@mysql.com>
+
+- marked /etc/logrotate.d/mysql as a config file (BUG 2156)
+
+* Fri Dec 12 2003 Lenz Grimmer <lenz@mysql.com>
+
+- fixed file permissions (BUG 1672)
+
+* Thu Dec 11 2003 Lenz Grimmer <lenz@mysql.com>
+
+- made testing for gcc3 a bit more robust
+
+* Fri Dec 05 2003 Lenz Grimmer <lenz@mysql.com>
+
+- added missing file mysql_create_system_tables to the server subpackage
+
+* Fri Nov 21 2003 Lenz Grimmer <lenz@mysql.com>
+
+- removed dependency on MySQL-client from the MySQL-devel subpackage
+  as it is not really required. (BUG 1610)
+
+* Fri Aug 29 2003 Lenz Grimmer <lenz@mysql.com>
+
+- Fixed BUG 1162 (removed macro names from the changelog)
+- Really fixed BUG 998 (disable the checking for installed but
+  unpackaged files)
+
+* Tue Aug 05 2003 Lenz Grimmer <lenz@mysql.com>
+
+- Fixed BUG 959 (libmysqld not being compiled properly)
+- Fixed BUG 998 (RPM build errors): added missing files to the
+  distribution (mysql_fix_extensions, mysql_tableinfo, mysqldumpslow,
+  mysql_fix_privilege_tables.1), removed "-n" from install section.
+
+* Wed Jul 09 2003 Lenz Grimmer <lenz@mysql.com>
+
+- removed the GIF Icon (file was not included in the sources anyway)
+- removed unused variable shared_lib_version
+- do not run automake before building the standard binary
+  (should not be necessary)
+- add server suffix '-standard' to standard binary (to be in line
+  with the binary tarball distributions)
+- Use more RPM macros (_exec_prefix, _sbindir, _libdir, _sysconfdir,
+  _datadir, _includedir) throughout the spec file.
+- allow overriding CC and CXX (required when building with other compilers)
+
+* Fri May 16 2003 Lenz Grimmer <lenz@mysql.com>
+
+- re-enabled RAID again
+
+* Wed Apr 30 2003 Lenz Grimmer <lenz@mysql.com>
+
+- disabled MyISAM RAID (--with-raid) - it throws an assertion which
+  needs to be investigated first.
+
+* Mon Mar 10 2003 Lenz Grimmer <lenz@mysql.com>
+
+- added missing file mysql_secure_installation to server subpackage
+  (BUG 141)
+
+* Tue Feb 11 2003 Lenz Grimmer <lenz@mysql.com>
+
+- re-added missing pre- and post(un)install scripts to server subpackage
+- added config file /etc/my.cnf to the file list (just for completeness)
+- make sure to create the datadir with 755 permissions
+
+* Mon Jan 27 2003 Lenz Grimmer <lenz@mysql.com>
+
+- removed unused CC and CXX variables
+- CFLAGS and CXXFLAGS should honor RPM_OPT_FLAGS
+
+* Fri Jan 24 2003 Lenz Grimmer <lenz@mysql.com>
+
+- renamed package "MySQL" to "MySQL-server"
+- fixed Copyright tag
+- added mysql_waitpid to client subpackage (required for mysql-test-run)
+
+* Wed Nov 27 2002 Lenz Grimmer <lenz@mysql.com>
+
+- moved init script from /etc/rc.d/init.d to /etc/init.d (the majority of
+  Linux distributions now support this scheme as proposed by the LSB either
+  directly or via a compatibility symlink)
+- Use new "restart" init script action instead of starting and stopping
+  separately
+- Be more flexible in activating the automatic bootup - use insserv (on
+  older SuSE versions) or chkconfig (Red Hat, newer SuSE versions and
+  others) to create the respective symlinks
+
+* Wed Sep 25 2002 Lenz Grimmer <lenz@mysql.com>
+
+- MySQL-Max now requires MySQL >= 4.0 to avoid version mismatches
+  (mixing 3.23 and 4.0 packages)
+
+* Fri Aug 09 2002 Lenz Grimmer <lenz@mysql.com>
+
+- Turn off OpenSSL in MySQL-Max for now until it works properly again
+- enable RAID for the Max binary instead
+- added compatibility link: safe_mysqld -> mysqld_safe to ease the
+  transition from 3.23
+
+* Thu Jul 18 2002 Lenz Grimmer <lenz@mysql.com>
+
+- Reworked the build steps a little bit: the Max binary is supposed
+  to include OpenSSL, which cannot be linked statically, thus trying
+  to statically link against a special glibc is futile anyway
+- because of this, it is not required to make yet another build run
+  just to compile the shared libs (saves a lot of time)
+- updated package description of the Max subpackage
+- clean up the BuildRoot directory afterwards
+
+* Mon Jul 15 2002 Lenz Grimmer <lenz@mysql.com>
+
+- Updated Packager information
+- Fixed the build options: the regular package is supposed to
+  include InnoDB and linked statically, while the Max package
+  should include BDB and SSL support
+
+* Fri May 03 2002 Lenz Grimmer <lenz@mysql.com>
+
+- Use more RPM macros (e.g. infodir, mandir) to make the spec
+  file more portable
+- reorganized the installation of documentation files: let RPM
+  take care of this
+- reorganized the file list: actually install man pages along
+  with the binaries of the respective subpackage
+- do not include libmysqld.a in the devel subpackage as well, if we
+  have a special "embedded" subpackage
+- reworked the package descriptions
+
+* Mon Oct  8 2001 Monty
+
+- Added embedded server as a separate RPM
+
+* Fri Apr 13 2001 Monty
+
+- Added mysqld-max to the distribution
+
+* Tue Jan 2  2001  Monty
+
+- Added mysql-test to the bench package
+
+* Fri Aug 18 2000 Tim Smith <tim@mysql.com>
+
+- Added separate libmysql_r directory; now both a threaded
+  and non-threaded library is shipped.
+
+* Wed Sep 29 1999 David Axmark <davida@mysql.com>
+
+- Added the support-files/my-example.cnf to the docs directory.
+
+- Removed devel dependency on base since it is about client
+  development.
+
+* Wed Sep 8 1999 David Axmark <davida@mysql.com>
+
+- Cleaned up some for 3.23.
+
+* Thu Jul 1 1999 David Axmark <davida@mysql.com>
+
+- Added support for shared libraries in a separate sub
+  package. Original fix by David Fox (dsfox@cogsci.ucsd.edu)
+
+- The --enable-assembler switch is now automatically disables on
+  platforms there assembler code is unavailable. This should allow
+  building this RPM on non i386 systems.
+
+* Mon Feb 22 1999 David Axmark <david@detron.se>
+
+- Removed unportable cc switches from the spec file. The defaults can
+  now be overridden with environment variables. This feature is used
+  to compile the official RPM with optimal (but compiler version
+  specific) switches.
+
+- Removed the repetitive description parts for the sub rpms. Maybe add
+  again if RPM gets a multiline macro capability.
+
+- Added support for a pt_BR translation. Translation contributed by
+  Jorge Godoy <jorge@bestway.com.br>.
+
+* Wed Nov 4 1998 David Axmark <david@detron.se>
+
+- A lot of changes in all the rpm and install scripts. This may even
+  be a working RPM :-)
+
+* Sun Aug 16 1998 David Axmark <david@detron.se>
+
+- A developers changelog for MySQL is available in the source RPM. And
+  there is a history of major user visible changed in the Reference
+  Manual.  Only RPM specific changes will be documented here.
diff --git a/scripts__mysqld_safe.sh__signals.patch b/scripts__mysqld_safe.sh__signals.patch
new file mode 100644 (file)
index 0000000..a3e9d14
--- /dev/null
@@ -0,0 +1,35 @@
+--- a/scripts/mysqld_safe.sh
++++ b/scripts/mysqld_safe.sh
+@@ -29,9 +29,6 @@ err_log=
+ syslog_tag_mysqld=mysqld
+ syslog_tag_mysqld_safe=mysqld_safe
+-trap '' 1 2 3 15                      # we shouldn't let anyone kill us
+-trap '' 13                              # not even SIGPIPE
+-
+ # MySQL-specific environment variable. First off, it's not really a umask,
+ # it's the desired mode. Second, it follows umask(2), not umask(3) in that
+ # octal needs to be explicit. Our shell might be a proper sh without printf,
+@@ -154,7 +151,7 @@ eval_log_error () {
+       # sed buffers output (only GNU sed supports a -u (unbuffered) option)
+       # which means that messages may not get sent to syslog until the
+       # mysqld process quits.
+-      cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error"
++      cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error & wait"
+       ;;
+     *)
+       echo "Internal program error (non-fatal):" \
+@@ -740,6 +737,13 @@ mysqld daemon not started"
+ fi
+ #
++# From now on, we catch signals to do a proper shutdown of mysqld
++# when signalled to do so.
++#
++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh & wait' 1 # HUP
++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM
++
++#
+ # Uncomment the following lines if you want all tables to be automatically
+ # checked and repaired during startup. You should add sensible key_buffer
+ # and sort_buffer values to my.cnf to improve check performance or require
diff --git a/spelling.patch b/spelling.patch
new file mode 100644 (file)
index 0000000..7978092
--- /dev/null
@@ -0,0 +1,244 @@
+--- a/libevent/event.3
++++ b/libevent/event.3
+@@ -253,7 +253,7 @@ the type of event which will be either
+ or
+ .Va EV_WRITE .
+ Additionally, an event which has registered interest in more than one of the
+-preceeding events, via bitwise-OR to
++preceding events, via bitwise-OR to
+ .Fn event_set ,
+ can provide its callback function with a bitwise-OR of more than one triggered
+ event.
+--- a/mysql-test/extra/rpl_tests/rpl_ddl.test
++++ b/mysql-test/extra/rpl_tests/rpl_ddl.test
+@@ -98,8 +98,8 @@
+ #       --> less switching of AUTOCOMMIT mode on master side.
+ #
+ #    4. Never use a test object, which was direct or indirect affected by a
+-#       preceeding test sequence again.
+-#       If one preceeding test sequence hits a (sometimes not visible,
++#       preceding test sequence again.
++#       If one preceding test sequence hits a (sometimes not visible,
+ #       because the sql error code of the statement might be 0) bug
+ #       and these rules are ignored, a following test sequence might earn ugly
+ #       effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/mysql-test/extra/rpl_tests/rpl_row_basic.test
++++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test
+@@ -221,7 +221,7 @@ INSERT INTO t7 VALUES (1,3), (2,6), (3,9
+ SELECT * FROM t7 ORDER BY C1;
+ # since bug#31552/31609 idempotency is not default any longer. In order
+-# the preceeding test INSERT INTO t7 to pass the mode is switched
++# the preceding test INSERT INTO t7 to pass the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+@@ -260,7 +260,7 @@ INSERT INTO t8 VALUES (1,2,3), (2,4,6),
+ SELECT * FROM t8 ORDER BY a;
+ # since bug#31552/31609 idempotency is not default any longer. In order
+-# the preceeding test INSERT INTO t8 to pass the mode is switched
++# the preceding test INSERT INTO t8 to pass the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+--- a/mysql-test/include/wait_until_count_sessions.inc
++++ b/mysql-test/include/wait_until_count_sessions.inc
+@@ -10,7 +10,7 @@
+ #    1. We wait for $current_sessions <= $count_sessions because in the use case
+ #       with count_sessions.inc before and wait_until_count_sessions.inc after
+ #       the core of the test it could happen that the disconnects of sessions
+-#       belonging to the preceeding test are not finished.
++#       belonging to the preceding test are not finished.
+ #       sessions at test begin($count_sessions) =  m + n
+ #       sessions of the previous test which will be soon disconnected = n (n >= 0)
+ #       sessions at test end ($current sessions, assuming the test disconnects
+--- a/mysql-test/suite/funcs_1/views/func_view.inc
++++ b/mysql-test/suite/funcs_1/views/func_view.inc
+@@ -285,7 +285,7 @@ INSERT INTO t1_values SET
+ #               other interesting value
+ #     numbers   -> 0
+ #     strings, blobs, binaries -> not full length of used data type, "exotic"
+-#                                 characters and preceeding and trailing spaces
++#                                 characters and preceding and trailing spaces
+ #     FIXME enum, set ??
+ INSERT INTO t1_values SET
+        my_char_30 = ' ---äÖüß@µ*$-- ',
+--- a/mysql-test/suite/funcs_1/views/views_master.inc
++++ b/mysql-test/suite/funcs_1/views/views_master.inc
+@@ -545,7 +545,7 @@ let $message= Testcase 3.3.1.7 ;
+ #                   view names are accepted, at creation time, alteration time,
+ #                   and drop time.
+ ###############################################################################
+-# Note(mleich): non-qualified view name means a view name without preceeding
++# Note(mleich): non-qualified view name means a view name without preceding
+ #               database name
+ --disable_warnings
+ DROP VIEW  IF EXISTS v1 ;
+--- a/mysql-test/suite/rpl/t/rpl_ddl.test
++++ b/mysql-test/suite/rpl/t/rpl_ddl.test
+@@ -13,10 +13,10 @@
+ #         sequences start.
+ #
+ #      2. Never use a test object, which was direct or indirect affected by a
+-#         preceeding test sequence again.
++#         preceding test sequence again.
+ #         Except table d1.t1 where ONLY DML is allowed.
+ #
+-#         If one preceeding test sequence hits a (sometimes not good visible,
++#         If one preceding test sequence hits a (sometimes not good visible,
+ #         because the sql error code of the statement might be 0) bug
+ #         and these rules are ignored, a following test sequence might earn ugly
+ #         effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
++++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
+@@ -239,7 +239,7 @@ sync_slave_with_master;
+ UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1;
+ SELECT * FROM t1 ORDER BY a;
+ # since bug#31552/31609 idempotency is not default any longer. In
+-# order for the preceeding test UPDATE t1 to pass, the mode is switched
++# order for the preceding test UPDATE t1 to pass, the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+ --echo **** On Master ****
+--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_ddl.test
++++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_ddl.test
+@@ -13,10 +13,10 @@
+ #         sequences start.
+ #
+ #      2. Never use a test object, which was direct or indirect affected by a
+-#         preceeding test sequence again.
++#         preceding test sequence again.
+ #         Except table d1.t1 where ONLY DML is allowed.
+ #
+-#         If one preceeding test sequence hits a (sometimes not good visible,
++#         If one preceding test sequence hits a (sometimes not good visible,
+ #         because the sql error code of the statement might be 0) bug
+ #         and these rules are ignored, a following test sequence might earn ugly
+ #         effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/sql/abstract_query_plan.cc
++++ b/sql/abstract_query_plan.cc
+@@ -336,7 +336,7 @@ namespace AQP
+       {
+         /*
+           use_quick == 2 means that the decision on which access method to use
+-          will be taken late (as rows from the preceeding operation arrive).
++          will be taken late (as rows from the preceding operation arrive).
+           This operation is therefor not pushable.
+         */
+         DBUG_PRINT("info",
+--- a/sql/ha_ndbcluster_push.cc
++++ b/sql/ha_ndbcluster_push.cc
+@@ -1271,7 +1271,7 @@ ndb_pushed_builder_ctx::build_key(const
+         if (m_join_scope.contain(referred_table_no))
+         {
+           // Locate the parent operation for this 'join_items[]'.
+-          // May refer any of the preceeding parent tables
++          // May refer any of the preceding parent tables
+           const NdbQueryOperationDef* const parent_op= m_tables[referred_table_no].m_op;
+           DBUG_ASSERT(parent_op != NULL);
+--- a/sql/log_event.cc
++++ b/sql/log_event.cc
+@@ -4607,7 +4607,7 @@ int Query_log_event::do_apply_event(Rela
+     if ((error= rows_event_stmt_cleanup(const_cast<Relay_log_info*>(rli), thd)))
+     {
+       const_cast<Relay_log_info*>(rli)->report(ERROR_LEVEL, error,
+-                  "Error in cleaning up after an event preceeding the commit; "
++                  "Error in cleaning up after an event preceding the commit; "
+                   "the group log file/position: %s %s",
+                   const_cast<Relay_log_info*>(rli)->get_group_master_log_name(),
+                   llstr(const_cast<Relay_log_info*>(rli)->get_group_master_log_pos(),
+--- a/sql/rpl_utility.cc
++++ b/sql/rpl_utility.cc
+@@ -1564,7 +1564,7 @@ bool Deferred_log_events::execute(Relay_
+ void Deferred_log_events::rewind()
+ {
+   /*
+-    Reset preceeding Query log event events which execution was
++    Reset preceding Query log event events which execution was
+     deferred because of slave side filtering.
+   */
+   if (!is_empty())
+--- a/sql/sql_optimizer.cc
++++ b/sql/sql_optimizer.cc
+@@ -971,7 +971,7 @@ JOIN::optimize()
+         }
+       }
+     }
+-    else if (order &&                      // ORDER BY wo/ preceeding GROUP BY
++    else if (order &&                      // ORDER BY wo/ preceding GROUP BY
+              (simple_order || skip_sort_order)) // which is possibly skippable
+     {
+       if (test_if_skip_sort_order(tab, order, m_select_limit, false, 
+--- a/sql/sql_rewrite.cc
++++ b/sql/sql_rewrite.cc
+@@ -40,7 +40,7 @@
+ /**
+-  Append a key/value pair to a string, with an optional preceeding comma.
++  Append a key/value pair to a string, with an optional preceding comma.
+   For numeric values.
+   @param           str                  The string to append to
+@@ -72,7 +72,7 @@ bool append_int(String *str, bool comma,
+ /**
+   Append a key/value pair to a string if the value is non-NULL,
+-  with an optional preceeding comma.
++  with an optional preceding comma.
+   @param           str                  The string to append to
+   @param           comma                Prepend a comma?
+--- a/sql/sql_yacc.cc
++++ b/sql/sql_yacc.cc
+@@ -39064,7 +39064,7 @@ yyreduce:
+             {
+               /*
+                 Not in trigger assigning value to new row,
+-                and option_type preceeding local variable is illegal.
++                and option_type preceding local variable is illegal.
+               */
+               my_parse_error(ER(ER_SYNTAX_ERROR));
+               MYSQL_YYABORT;
+--- a/sql/sql_yacc.yy
++++ b/sql/sql_yacc.yy
+@@ -14559,7 +14559,7 @@ opt_var_ident_type:
+         | SESSION_SYM '.' { $$=OPT_SESSION; }
+         ;
+-// Option values with preceeding option_type.
++// Option values with preceding option_type.
+ option_value_following_option_type:
+           internal_variable_name equal set_expr_or_default
+           {
+@@ -14576,7 +14576,7 @@ option_value_following_option_type:
+             {
+               /*
+                 Not in trigger assigning value to new row,
+-                and option_type preceeding local variable is illegal.
++                and option_type preceding local variable is illegal.
+               */
+               my_parse_error(ER(ER_SYNTAX_ERROR));
+               MYSQL_YYABORT;
+@@ -14584,7 +14584,7 @@ option_value_following_option_type:
+           }
+         ;
+-// Option values without preceeding option_type.
++// Option values without preceding option_type.
+ option_value_no_option_type:
+           internal_variable_name equal
+           {
+--- a/storage/myisam/mi_rnext.c
++++ b/storage/myisam/mi_rnext.c
+@@ -65,7 +65,7 @@ int mi_rnext(MI_INFO *info, uchar *buf,
+       Normally SQL layer would never request "search next" if
+       "search first" failed. But HANDLER may do anything.
+-      As mi_rnext() without preceeding mi_rkey()/mi_rfirst()
++      As mi_rnext() without preceding mi_rkey()/mi_rfirst()
+       equals to mi_rfirst(), we must restore original state
+       as if failing mi_rfirst() was not called.
+     */
diff --git a/wsrep_sst_mysqldump.patch b/wsrep_sst_mysqldump.patch
new file mode 100644 (file)
index 0000000..6b97076
--- /dev/null
@@ -0,0 +1,31 @@
+diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh
+index 89eb755..c20d9fa 100644
+--- a/scripts/wsrep_sst_mysqldump.sh
++++ b/scripts/wsrep_sst_mysqldump.sh
+@@ -53,6 +53,8 @@ then
+     exit $EINVAL
+ fi
++MYSQL_APPS_PREFIX="nice -n 15 ionice -c2 -n7"
++
+ # Check client version
+ CLIENT_MINOR=$(mysql --version | cut -d ' ' -f 6 | cut -d '.' -f 2)
+ if [ $CLIENT_MINOR -lt "6" ]
+@@ -73,7 +75,7 @@ if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi
+ STOP_WSREP="SET wsrep_on=OFF;"
+ # NOTE: we don't use --routines here because we're dumping mysql.proc table
+-MYSQLDUMP="$MYSQLDUMP $AUTH -S$WSREP_SST_OPT_SOCKET \
++MYSQLDUMP="$MYSQL_APPS_PREFIX $MYSQLDUMP $AUTH -S$WSREP_SST_OPT_SOCKET \
+ --add-drop-database --add-drop-table --skip-add-locks --create-options \
+ --disable-keys --extended-insert --skip-lock-tables --quick --set-charset \
+ --skip-comments --flush-privileges --all-databases --events"
+@@ -98,7 +100,7 @@ DROP PREPARE stmt;"
+ SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';"
+-MYSQL="$MYSQL_CLIENT $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\
++MYSQL="$MYSQL_APPS_PREFIX $MYSQL_CLIENT $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\
+ "--disable-reconnect --connect_timeout=10"
+ # need to disable logging when loading the dump